Hi there I am trying to use handsontables which works fine when I hard code the data but when I try use a schema which is what i need cant get it to work. I have been following this old post Meteor Handsontable example. I have done everything except change
// Remove "var" from Handsontable declaration to add to global scope
var Handsontable = function (rootElement, userSettings) {
...
// New code
Handsontable = function (rootElement, userSettings) {
...
I cant seem to find this anywhere.
What I have is.
products.js
import { Mongo } from 'meteor/mongo';
import { check } from 'meteor/check';
export const Product = new Mongo.Collection('product');
ProducSchema = new SimpleSchema({
name: {
type: String,
},
m1: {
type: Number,
defaultValue: 0
},
m2: {
type: Number,
defaultValue: 0
},
m3: {
type: Number,
defaultValue: 0
},
m4: {
type: Number,
defaultValue: 0
},
});
Product.allow({
insert: function (userId, doc) {
// the user must be logged in, and the document must be owned by the user
return !!userId;
},
update: function (userId, doc) {
// can only change your own documents
return !!userId;
},
remove: function (userId, doc) {
// can only remove your own documents
return doc.owner === userId;
},
fetch: ['owner']
});
Product.attachSchema( ProducSchema );
productSingle.js
import { Template } from 'meteor/templating';
import { Meteor } from 'meteor/meteor';
import { Product } from '../../../../../api/lists/Products.js';
import './ProductSingle.html';
if (Meteor.isClient) {
Template.ProductSingle.onCreated(function() {
var self = this;
self.autorun(() => {
self.subscribe('product');
})
});
Template.ProductSingle.rendered = function() {
var myData = []; // Need this to create instance
var container = document.getElementById("productSingle");
var hot = new Handsontable(container, { // Create Handsontable instance
data: myData,
startRows: 5,
startCols: 5,
colHeaders: true,
rowHeaders: true,
minSpareRows: 1,
contextMenu: true,
afterChange: function(change, source) { // "change" is an array of arrays.
if (source !== "loadData") { // Don't need to run this when data is loaded
for (i = 0; i < change.length; i++) { // For each change, get the change info and update the record
var rowNum = change[i][0]; // Which row it appears on Handsontable
var row = myData[rowNum]; // Now we have the whole row of data, including _id
var key = change[i][1]; // Handsontable docs calls this "prop"
var oldVal = change[i][2];
var newVal = change[i][3];
var setModifier = {
$set: {}
}; // Need to build $set object
setModifier.$set[key] = newVal; // So that we can assign 'key' dynamically using bracket notation of JavaScript object
MyCollection.update(row._id, setModifier);
}
}
}
});
Tracker.autorun(function() { // Tracker function for reactivity
myData = Product.find().fetch(); // Tie in our data
hot.loadData(myData);
console.log(myData);
});
};
}
This doesn't show any table just the the first row header like so .
If i click on this is get a error:
awsp_handsontable.js?hash=45775ff…:25594 Uncaught Error: column 0 does not exist(…)
If someone could help me figure this out would be great this has been a big road block for me so far
Related
I have two Mongoose model schemas as follows. The LabReport model contains an array of the referenced SoilLab model. There is a static method in the SoilLab model that I was using to select which fields to display when LabReport is retrieved.
//LabReport.js
var mongoose = require("mongoose");
var SoilLab = mongoose.model("SoilLab");
var LabReportSchema = new mongoose.Schema(
{
labFarm: { type: mongoose.Schema.Types.ObjectId, ref: "Farm" },
testName: { type: String },
soilLabs: [{ type: mongoose.Schema.Types.ObjectId, ref: "SoilLab" }],
},
{ timestamps: true, usePushEach: true }
);
LabReportSchema.methods.toLabToJSON = function () {
return {
labReport_id: this._id,
testName: this.testName,
soilLabs: this.soilLabs.SoilToLabJSON(),
};
};
mongoose.model("LabReport", LabReportSchema);
//SoilLab.js
var mongoose = require("mongoose");
var SoilLabSchema = new mongoose.Schema(
{
description: { type: String },
sampleDate: { type: Date },
source: { type: String },
},
{ timestamps: true, usePushEach: true }
);
SoilLabSchema.methods.SoilToLabJSON = function () {
return {
description: this.description,
sampleDate: this.sampleDate,
source: this.source,
};
};
mongoose.model("SoilLab", SoilLabSchema);
When I try to retrieve the LabReport, I get "this.soilLabs.SoilToLabJSON is not a function". This is how I'm trying to retrieve LabReport.
//labReports.js
...
return Promise.all([
LabReport.find()
.populate("soilLabs")
.exec(),
LabReport.count(query).exec(),
req.payload ? User.findById(req.payload.id) : null,
]).then(function (results) {
var labReports = results[0];
var labReportsCount = results[1];
var user = results[2];
return res.json({
labReports: labReports.map(function (labReport) {
return labReport.toLabToJSON(user); //This cant find SoilToLabJSON
}),
If I remove the .SoilToLabJSON in LabReport.js and just call this.soilLabs, it works but outputs all of the soilLabs data which will become an issue when I have the model completed with more data. I have dug into statics vs methods a little and tried changing it to statics but it didn't work.
I get the soilLabs to populate but not sure why the .SoilToLabJSON method is inaccessible at this point. Do I need to find() or populate the soilLab differently? Is the method incorrect?
labReport.toLabToJSON is passing an array and that was causing the error for me. I simply edited the LabReport.js to the following to take the array and map it to SoilToLabJSON properly.
myTestSoilLabOutput = function (soilLabs) {
var test = soilLabs.map(function (soilLab) {
return soilLab.SoilToLabJSON();
});
return test;
Changed the LabReportSchema.methods.toLabToJSON to:
LabReportSchema.methods.toLabToJSON = function () {
return {
labReport_id: this._id,
testName: this.testName,
soilLabs: myTestSoilLabOutput(this.soilLabs),
};
};
I am using nativescript core with plain javascript. But I do not think this is where the issue lies. The basis of my problem is I am trying to add a new object to a global array and when I do, my previous data keeps getting overwritten with the new object.
I have tried a normal array.push({data}) and the ES6 spread [...array, {data}]. Both of these methods ended up overwriting the previous data in the array with the new object.
record-page.js
// import statements
// variables
// 'global' array of markers.
var markers = [];
// this function opens a custom modal
function addObsticalTapped(args) {
// close the popup
var page = args.object.page;
var popup = page.getViewById("trailNotesPopup");
isShown = false;
popup.animate({
translate: {
x: 0,
y: 500
},
duration: 300,
curve: enums.AnimationCurve.easeInOut
});
var mainView = args.object;
var context = {};
geolocation
.getCurrentLocation({
desiredAccuracy: Accuracy.high
})
.then(loc => {
curLoc = loc;
});
mainView.showModal(obsticalModal, context, addObsticalIcon, false);
}
exports.addObsticalTapped = addObsticalTapped;
// callback function when the modal is closed
function addObsticalIcon(didConfirm, data) {
if (didConfirm) {
// this is where the problem is, the markers array is being overwritten
// when adding another marker
markers = [...markers, {
type: "obstical",
location: {
lat: curLoc.latitude,
lng: curLoc.longitude
},
data: data,
trail_id: ""
}];
map.addMarkers([{
id: markerID,
lat: curLoc.latitude,
lng: curLoc.longitude,
//icon: "res://obstical_icon"
iconPath: "./icons/obstical_icon_marker.png"
}]);
markerID++;
console.log(JSON.stringify(markers));
} else {
console.log("closed");
}
}
obstical-modal.js
function onShownModally(args) {
const context = args.context;
closeCallback = args.closeCallback;
const page = args.object;
vm = observableModule.fromObject(context);
vm.set("oneSelected", oneSelected ? oneOn : oneOff);
vm.set("threeSelected", threeSelected ? threeOn : threeOff);
vm.set("sixSelected", sixSelected ? sixOn : sixOff);
vm.set("nineSelected", nineSelected ? nineOn : nineOff);
page.bindingContext = vm;
}
exports.onShownModally = onShownModally;
function onCancel(args) {
closeCallback(false, {});
}
exports.onCancel = onCancel;
function onSubmit(args) {
var page = args.object.page;
var textField = page.getViewById("info");
data.info = textField.text;
closeCallback(true, data);
}
exports.onSubmit = onSubmit;
What I expect to happen:
obstacle one has a difficulty of 1 and info of "hello world"
then add it to the array and the array is correct.
Then I add another obstacle with a difficulty of 3 and info of "hello code"
When this gets added to the array, the array then looks like:
[{"type":"obstical","data":{"difficulty":3,"info":"hello code"}},{"type":"obstical","data":{"difficulty":3,"info":"hello code"}}]
I was going to put this as a comment but wanted to show you an example of what I believe you are doing wrong by writing some simplified version of the code you have.
const data = {
difficulty: '1',
info: 'hello code',
};
const markers = [];
markers.push({
type: 'obstical',
data: data,
});
// Here is the problem. The problem is not related to the array adding
data.difficulty = '3';
markers.push({
type: 'obstical',
data: data,
});
The issue has nothing to do with how you add to the array but that you are mutating your original data object. The solution would be the following
const data = {
difficulty: '1',
info: 'hello code',
};
const markers = [];
markers.push({
type: 'obstical',
data: data,
});
// create a new object instead of mutating the existing one
const newData = {
...data,
difficulty: '3',
};
markers.push({
type: 'obstical',
data: newData,
});
We are coming from .NET developers and trying to figure out this sample application Telerik Platform work utilizing Cordova (hybrid mode) especially for JavaScript.
The code is what we believe is Model for handling the activities. Is this correct? The syntax is a bit weird. It looks different from what we know. Can't figure out which one is method and which one is property.
It seems there is no more information about this type of Javascript. Where can I find more about this info beside Telerik site.
/**
* Activities view model
*/
var app = app || {};
app.Activities = (function () {
'use strict'
// Activities model
var activitiesModel = (function () {
var activityModel = {
id: 'Id',
fields: {
Text: {
field: 'Text',
defaultValue: ''
},
CreatedAt: {
field: 'CreatedAt',
defaultValue: new Date()
},
Picture: {
fields: 'Picture',
defaultValue: null
},
UserId: {
field: 'UserId',
defaultValue: null
},
Likes: {
field: 'Likes',
defaultValue: []
}
},
CreatedAtFormatted: function () {
return app.helper.formatDate(this.get('CreatedAt'));
},
PictureUrl: function () {
return app.helper.resolvePictureUrl(this.get('Picture'));
},
User: function () {
var userId = this.get('UserId');
var user = $.grep(app.Users.users(), function (e) {
return e.Id === userId;
})[0];
return user ? {
DisplayName: user.DisplayName,
PictureUrl: app.helper.resolveProfilePictureUrl(user.Picture)
} : {
DisplayName: 'Anonymous',
PictureUrl: app.helper.resolveProfilePictureUrl()
};
},
isVisible: function () {
var currentUserId = app.Users.currentUser.data.Id;
var userId = this.get('UserId');
return currentUserId === userId;
}
};
// Activities data source. The Backend Services dialect of the Kendo UI DataSource component
// supports filtering, sorting, paging, and CRUD operations.
var activitiesDataSource = new kendo.data.DataSource({
type: 'everlive',
schema: {
model: activityModel
},
transport: {
// Required by Backend Services
typeName: 'Activities'
},
change: function (e) {
if (e.items && e.items.length > 0) {
$('#no-activities-span').hide();
} else {
$('#no-activities-span').show();
}
},
sort: { field: 'CreatedAt', dir: 'desc' }
});
return {
activities: activitiesDataSource
};
}());
// Activities view model
var activitiesViewModel = (function () {
// Navigate to activityView When some activity is selected
var activitySelected = function (e) {
app.mobileApp.navigate('views/activityView.html?uid=' + e.data.uid);
};
// Navigate to app home
var navigateHome = function () {
app.mobileApp.navigate('#welcome');
};
// Logout user
var logout = function () {
app.helper.logout()
.then(navigateHome, function (err) {
app.showError(err.message);
navigateHome();
});
};
return {
activities: activitiesModel.activities,
activitySelected: activitySelected,
logout: logout
};
}());
return activitiesViewModel;
}());
Yes this are javascript objects. They seem a little different because they are being created using what is known as the Functional Pattern. One of its principles is to emulate private data as everything in javascript is declared in the global scope except whatever you declared inside a function, which creates a new scope hence it cannot be seen from the outside. You can google it or if your willing to document yourself i suggest you to read "Javascript: The Good Parts from Douglas Crockford" as it contains almost everything to be considered best practices for javascript these days.
I am trying to build datagrid with sorting, searching and paging enabled. Therefore, I am using fuelux-datagrid.
MY backbone view looks like this:
var app = app || {};
$(function ($) {
'use strict';
// The Players view
// ---------------
app.PlayersView = Backbone.View.extend({
template: _.template( $("#player-template").html() ),
initialize: function () {
if(this.collection){
this.collection.fetch();
}
this.listenTo(this.collection, 'all', this.render);
},
render: function () {
this.$el.html( this.template );
var dataSource = new StaticDataSource({
columns: [
{
property: 'playername',
label: 'Name',
sortable: true
},
{
property: 'age',
label: 'A',
sortable: true
}
],
data: this.collection.toJSON(),
delay: 250
});
$('#MyGrid').datagrid({
dataSource: dataSource,
stretchHeight: true
});
}
});
});
The player template just contain the template as given in fuelux datagrid . My routing code somewhere instantiate app.playerview with collection as
new app.PlayersView({
collection : new app.PlayersCollection
}));
My players collection contains list of player model as below
[{
"id":1,
"playername":"rahu",
"age":13
},
{
"id":2,
"playername":"sahul",
"age":18
},
{
"id":3,
"playername":"ahul",
"age":19
}]
My datasource class/function to construct datasoruce with columns and data method is as given in datasource constructor
However, I get the error the " datasource in not defined ". Can anybody help me?
I just wanted to hack the code so that instead of datasource constructed from local data.js in given example, I want to construct the datasource so that it takes data from playercollection.
Also, how to add the one extra column so that we can put edit tag insdie and its should be able to edit the particular row model on clicking that edit.
I have been stucking around these a lot. It would be great help to figure out the answer.
I was stucking around datasource.
I modified the datasource as follows and then it worked.
var StaticDataSource = function (options) {
this._formatter = options.formatter;
this._columns = options.columns;
this._delay = options.delay || 0;
this._data = options.data;
};
StaticDataSource.prototype = {
columns: function () {
return this._columns;
},
data: function (options, callback) {
var self = this;
setTimeout(function () {
var data = $.extend(true, [], self._data);
// SEARCHING
if (options.search) {
data = _.filter(data, function (item) {
var match = false;
_.each(item, function (prop) {
if (_.isString(prop) || _.isFinite(prop)) {
if (prop.toString().toLowerCase().indexOf(options.search.toLowerCase()) !== -1) match = true;
}
});
return match;
});
}
// FILTERING
if (options.filter) {
data = _.filter(data, function (item) {
switch(options.filter.value) {
case 'lt5m':
if(item.population < 5000000) return true;
break;
case 'gte5m':
if(item.population >= 5000000) return true;
break;
default:
return true;
break;
}
});
}
var count = data.length;
// SORTING
if (options.sortProperty) {
data = _.sortBy(data, options.sortProperty);
if (options.sortDirection === 'desc') data.reverse();
}
// PAGING
var startIndex = options.pageIndex * options.pageSize;
var endIndex = startIndex + options.pageSize;
var end = (endIndex > count) ? count : endIndex;
var pages = Math.ceil(count / options.pageSize);
var page = options.pageIndex + 1;
var start = startIndex + 1;
data = data.slice(startIndex, endIndex);
if (self._formatter) self._formatter(data);
callback({ data: data, start: start, end: end, count: count, pages: pages, page: page });
}, this._delay)
}
};
Infact, I just removed following code and its associated braces.
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
define(['underscore'], factory);
} else {
root.StaticDataSource = factory();
}
}(this, function () {
I dont know what exactly the above code is doing an what dependdencies they have over.
Say, we have this in the store:
[
{
name: 'Criteria 1',
status: 'In'
},
{
name: 'Criteria 2',
status: 'Out'
},
...
]
We need to display criteria that are In in one list and those that are Out in another from that store. Is it possible to do?
A few months ago I've created a FilteredStore class for Sencha.
It's not perfect, but might be very usefull to you.
It basically allows you to create a new store by filtering another one.
Ext.define('Ext.data.FilteredStore', {
extend: 'Ext.data.Store',
///////////////////////////////////////////////////////////////////////////
// Configuration
config: {
model: 'Ext.data.Model',
sourceStore: undefined,
filter: undefined
},
///////////////////////////////////////////////////////////////////////////
// Fields
sourceStore: undefined,
///////////////////////////////////////////////////////////////////////////
// Configuration methods
updateSourceStore: function (newValue, oldValue) {
//TODO: Remove hooks from old store (oldValue)
// See if we've received a valid source store
if (!newValue)
return;
// Resolve the source store
this.sourceStore = Ext.data.StoreManager.lookup(newValue);
if (!this.sourceStore || !Ext.isObject(this.sourceStore) || !this.sourceStore.isStore)
Ext.Error.raise({ msg: 'An invalid source store (' + newValue + ') was provided for ' + this.self.getName() });
// Listen to source store events and copy model
this.setModel(this.sourceStore.getModel());
this.sourceStore.on({
addrecords: 'sourceStoreAdded',
removerecords: 'sourceStoreRemoved',
refresh: 'sourceStoreChanged',
scope: this
});
// Load the current data
this.sourceStoreChanged();
},
updateFilter: function () {
// Load the current data
this.sourceStoreChanged();
},
///////////////////////////////////////////////////////////////////////////
// Store overrides
fireEvent: function (eventName, me, record) {
// Intercept update events, remove rather than update if record is no longer valid
var filter = this.getFilter();
if (filter && eventName === 'updaterecord' && !filter(record))
this.remove(record);
else
this.callParent(arguments);
},
///////////////////////////////////////////////////////////////////////////
// Event handlers
sourceStoreAdded: function (sourceStore, records) {
var filter = this.getFilter();
if (!filter)
return;
// Determine which records belong in this store
var i = 0, len = records.length, record, newRecords = [];
for (; i < len; i++) {
record = records[i];
// Don't add records already in the store
if (this.indexOf(record) != -1)
continue;
if (filter(record))
newRecords.push(record);
}
// Add the new records
if (newRecords.length)
this.add(newRecords);
},
sourceStoreRemoved: function (sourceStore, records) {
this.remove(records);
},
sourceStoreChanged: function () {
// Clear the store
this.removeAll();
var records = [],
i, all, record,
filter = this.getFilter();
// No filter? No data
if (!filter)
return;
// Collect and filter the current records
all = this.sourceStore.getAll();
for (i = 0; i < all.length; i++) {
record = all[i];
if (filter(record))
records.push(record);
}
// Add the records to the store
this.add(records);
}
});
Example usage code:
Ext.define('My.store.ActiveItems', {
extend: 'Ext.data.FilteredStore',
config: {
sourceStore: 'Items',
filter: function (record) { return record.get('IsActive'); }
}
});
extjs 5 added chained stores for this very scenario
http://dev.sencha.com/ext/5.0.0/examples/kitchensink/#binding-chained-stores
Ext.define('KitchenSink.view.binding.ChainedStoresModel', {
extend: 'Ext.app.ViewModel',
alias: 'viewmodel.binding.chainedstores',
stores: {
everyone: {
model: 'Person',
data: KitchenSink.model.Person.generateData(15, 10)
},
adults: {
source: '{everyone}',
filters: [{
property: 'age',
value: 18,
operator: '>='
}],
sorters: [{
property: 'age',
direction: 'ASC'
}]
}
}
});
This is not possible. When you tie a list to a store, it reflects all the changes made to that store. They are always in sync. When you put a filter on a store, the items[] array of that store is changed, and that will change any list that is attached to that store.
(Similarly, if you tie a chart to a store, the chart is automatically updated as the store is updated.)
You could have two stores that are initially filled (and maintained) with the same data, and then apply different filters to the two stores.
Try applying filter to the store. May be this will work.
var newstore=Ext.getStore("Store"); // If you have Store.js
newstore.clearFilter();//clear previous filter
newstore.filter('status', 'In');