dgrid JsonRest store not working - asynchronous

I have the following:
require([
"dojo/dom",
"dojo/on",
"dojo/store/Observable",
"dojo/store/JsonRest",
"dojo/store/Memory",
"dgrid/OnDemandGrid"
], function (dom, on, Observable, JsonRest, Memory, OnDemandGrid) {
var store = new JsonRest({
target: 'client/list',
idProperty: 'id'
});
var grid = new OnDemandGrid({
columns: {
"id": "ID",
"number": "Name",
"description": "Description"
},
sort: "lastName",
store: store
}, "grid");
});
client/list is a rest url returning a json object {data:[...]}, but the content of the list never shows up :/
I think the problem is caused by the async data loading, because with a json hard coded object the content show up
EDIT :
I've succeeded in achieving this by using a dojo/request, but the JsonRest shouldn't normally act the same way ? Can someone point me to the right direction ?
require([
'dojo/dom',
'dojo/on',
'dojo/store/Memory',
'dojo/request',
'dgrid/OnDemandGrid'
], function (dom, on, Memory, request, OnDemandGrid) {
request('client/list', {
handleAs: 'json'
}).then(function (response) {
// Once the response is received, build an in-memory store with the data
var store = new Memory({ data: response });
// Create an instance of OnDemandGrid referencing the store
var grid = new OnDemandGrid({
store: store,
sort: 'id', // Initialize sort on id, ascending
columns: {
'id': 'ID',
'number': 'Name',
'description': 'Description'
}
}, 'grid');
console.log(store);
on(dom.byId('queryForm'), 'input', function (event) {
event.preventDefault();
grid.set('query', {
// Pass a RegExp to Memory's SimpleQueryEngine
// Note: this code does not go out of its way to escape
// characters that have special meaning in RegExps
description: new RegExp(this.elements.last.value, 'i')
});
});
on(dom.byId('queryForm'), 'reset', function () {
// Reset the query when the form is reset
grid.set('query', {});
});
});
});

Ok problem found :/
My "client/list" url was returning a json object like this:
{data: [{id:"1", label: "test"}, {id:"2", label: "test"}]}
Turns out that the JsonRest object is already encapsulating data in a data node, so by returning a json like this:
{[{id:"1", label: "test"}, {id:"2", label: "test"}]}
everything worked fine :)

Related

Displaying name and selecting id on select for Twitter Typeahead

I am trying to implement twitter typeahead into my project, having remote as the source. I am able to make the connection between the front end query text and the sql. The return response looks like this:
[
{
id: 1,
name: 'user one'
},
{
id: 2,
name: 'user two'
}
..
]
The typeahead displays the matching items but it includes the id along with the names in the selection, instead of just the name. Second, I want to get the id value on select but the :select always gives the name value instead of the id.
here is my code:
var source = new Bloodhound({
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('name'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
remote: {
url:"{{ path('user_typeahead') }}"+'?string=%QUERY', // twig path
wildcard: '%QUERY',
filter: function (results) {
// Map the remote source JSON array to a JavaScript object array
return $.map(results, function (result) {
return {
value: result
};
});
}
}
});
// Initialize the Bloodhound suggestion engine
source.initialize();
$('#typeahead').typeahead(null, {
display: 'value',
source: source.ttAdapter(),
limit:5,
highlight: true,
hint: true
});
$('#typeahead').bind('typeahead:select', function(ev, suggestion) {
console.log(suggestion);
});
Try this,
Display should be set to the property of the json object. display: 'id'
Chain the custom event. Access your id from suggestion.id.
$('#typeahead').typeahead(null, {
display: 'id',
source: source.ttAdapter(),
limit:5,
highlight: true,
hint: true
}).bind('typeahead:select', function(ev, suggestion) {
console.log(suggestion);
});

How to where do i process my data with observable .map and .subscribe

I'm retriving some data from my API:
[
{
"id": 1,
"lat": 50.607084,
"lng": 3.043099
},
{
"id": 2,
"lat": 50.607084,
"lng": 3.043099
},
]
I'd like to process the data only with reactive programing so that inside my request, google map markers get created.
this.http.get('http://api/getData')
.map(res => {
return res.json()
})
.subscribe(
data => {
console.log(data);
});
when doing this i'm getting a lot of objects, i could not fin a way to log or isolate only the latitude (i get "unknown").
I'd like to be able to put a function inside the ".map" (observable ?) that will get all variable,
and create markersOptions that i'll put in an array.
let markerOptions: GoogleMapsMarkerOptions = {
position: latlng,
title: 'id'
};
From wath i've seen on google, most of people prefer put the object in a private variable and i assume take care of it, in an other function.
What you need to do is mapping the array retrieved from the server to a list of GoogleMapsMarkerOptions. So, (I don't know the constructor of GoogleMapsMarkerOptions) something like:
this.http.get('http://api/getData')
.map(res => {
return res.json().map(x => {
return new GoogleMapsMarkerOptions({
title: x.it,
position: new GoogleMapsLatLng(x.lat, x.lng)
});
});
})
.subscribe(
data => {
console.log(data);
});
The second map is a standard javascript method (not rxjs). If you need to support old browsers you can use lodash or underscore.

Populating SELECT options from database in SimpleSchema

Using SimpleSchema in Meteor with the AutoForm + Select2 plugins , i am trying to generate the Options for a Select field from the database.
The 'occupation' collection is published, and a collection 'Occupation' is defined in Meteor.
In SimpleSchema I have this:-
occupations: {
type: [String],
optional:true,
label: 'Occupation',
autoform:{
type:"select2",
placeholder: 'Comma spaced list of occupations',
options: function () {
Meteor.subscribe('occupations');
return Occupations.find({});
}
}
},
But it does not return the collection results, and crashes the application without an error message.
It seems the best way to handle this is to supply the options list through a helper.
{{> afQuickField name='occupations' multiple=true tags=true options=listOccupations}}
Where listOccupations is a helper within the template containing the form.
Template.myForm.helpers({
listOccupations: function () {
Meteor.subscribe('occupations');
return Occupations.find({}).fetch();
}
});
And we remove the options object from the schena
occupations: {
type: [String],
optional:true,
label: 'Occupation',
autoform:{
type:"select2",
placeholder: 'Comma spaced list of occupations',
}
},
Have you tried, this approach:
autoform: {
options: {
var occupations = [];
Occupations.find().map(function(occ) {
occupations.push(
{label: occ.description, value: occ._id}
);
});
return occupations;
}
}
hope this helps..
I had the same issue. I'm defining my collections schema in /lib/collections folder, and that is running on both server and client side. Given that, the console.log that I had was printing the correct values on server side and an empty array on client side.
What I did was:
if (Meteor.isClient){
Meteor.subscribe('service-categories-list', {
onReady: function(){
const serviceCategories = ServiceCategories.find({}).map(function(item, index) {
return {
label: item.name,
value: item.slug
};
});
Schema2._schema.type.autoform.options = serviceCategories;
}
})
}
I know that using the _schema is not a good idea, but I accept suggestions :)

Meteor array returned as string to this

In my Meteor app, I have a simple array field called relatedSentences. It is defined using SimpleSchema
relatedSentences: {
type: [String],
label: "Related Sentence",
optional: false,
defaultValue: []
},
It's data can be seen in the Mongo console:
"_id" : "ei96FFfFdmhPXxRWb",
"sentence" : "the newest one",
"relatedSentences" : [
"Ls6EyBkbcotcyfLyw",
"6HKQroCjZhG9YCuBt"
],
"createdAt" : ISODate("2015-10-25T11:21:25.338Z"),
"updatedAt" : ISODate("2015-10-25T11:41:39.691Z")
But when I try to access this field using this, it is returned as a raw string.
Template.showSentence.helpers({
translations: function() {
console.log("related: " + this.relatedSentences);
Meteor.subscribe('sentences', function() {
var relatedSentences = Sentences.find({_id: {$in: this.relatedSentences} }).fetch();
console.log("rel count" + relatedSentences.length);
return relatedSentences;
});
}
});
In the console I get an error. See the return value from the this.relatedSentences. It is the contents of the array as a string, with a comma interpolated.
related: Ls6EyBkbcotcyfLyw,6HKQroCjZhG9YCuBt
selector.js:595 Uncaught Error: $in needs an array
Not sure what is going on here.
Some Progress
I have made some progress, but not yet at a solution. By adding blackbox: true to the SimpleSchema definition, what looks like an array is now returned... but alas it is still failing. See below.
relatedSentences: {
type: [String],
label: "Related Sentence",
optional: false,
blackbox: true,
defaultValue: []
},
Now I get the results below in the console. The values are now being returned as a quoted array, which is what I expected. But the $in is still not seeing it as an array.
["Ls6EyBkbcotcyfLyw", "6HKQroCjZhG9YCuBt"]
selector.js:595 Uncaught Error: $in needs an array
How did the data get populated
In answer to #Kyll - this is how the data was originally populated. I am using AutoForm,
{{> afQuickField name='relatedSentences.0' value=this._id type="hidden"}}
but then adding the array data via a hook.
AutoForm.addHooks('translateForm', {
onSuccess: function (operation, result, template) {
Meteor.subscribe('sentences', function() {
var translatedSentence = Sentences.findOne(result);
var originalSentenceId = translatedSentence.relatedSentences[0]
Sentences.update(
{ _id: originalSentenceId},
{ $push: { relatedSentences: result}
});
Router.go('showSentence',{ _id: originalSentenceId } );
});
}
});
The problem here is the scope of this. You are referring to it inside the subscribe function, where this has a different context. Set a varibale to this in the context where it works, then use that variable instead:
Template.showSentence.helpers({
translations: function() {
console.log("related: " + this.relatedSentences);
var this_related_sentences = this.relatedSentences;
Meteor.subscribe('sentences', function() {
var relatedSentences = Sentences.find({_id: {$in: this_related_sentences} }).fetch();
console.log("rel count" + relatedSentences.length);
return relatedSentences;
});
}
});

Grid content JSON conversion

I have a grid where user and add new rows as many as they want. After adding all the rows, they click the "Save" button. On Save button click, I want to send all the data entered by the user in JSON format to the server side code (i.e. a servlet in my case)
Below is the model and store definition:
Ext.define('Plant', {
extend: 'Ext.data.Model',
fields: [
// the 'name' below matches the tag name to read, except 'availDate'
// which is mapped to the tag 'availability'
{name: 'common', type: 'string'},
{name: 'botanical', type: 'string'},
{name: 'light'},
{name: 'price', type: 'float'},
// dates can be automatically converted by specifying dateFormat
{name: 'availDate', mapping: 'availability', type: 'date', dateFormat: 'm/d/Y'},
{name: 'indoor', type: 'bool'}
]
});
// create the Data Store
var store = Ext.create('Ext.data.Store', {
// destroy the store if the grid is destroyed
autoDestroy: true,
model: 'Plant'
});
On click of the save button, I am able to get the store like this:
{
text: 'Save',
handler : function(){
//Getting the store
var records = grid.getStore();
console.log(records.getCount());
Ext.Ajax.request({
url: '/CellEditing/CellEditingGridServlet',
method: 'POST',
jsonData: {
//How to assign the store here such that
//it is send in a JSON format to the server?
},
callback: function (options, success, response) {
}
});
}
But I don't know like how to convert the store content into JSON and send it in the jsonData of the ajax request.
I want the JSON data something like this in the server side:
{"plantDetails":
[
{
"common": Plant1,
"light": 'shady',
"price": 25.00,
"availDate": '05/05/2013',
"indoor": 'Yes'
},
{
"common": Plant2,
"light": 'most shady',
"price": 15.00,
"availDate": '12/09/2012',
"indoor": 'No'
},
]
}
Please let me know how to achieve this.
Regards,
Agreed with Neil, the right way to do this is through an editable store outfited with a proxy and a writer. See example here: http://docs.sencha.com/ext-js/4-1/#!/example/grid/cell-editing.html
Store
writer :
{
type : 'json',
allowSingle : true
}
Experiment with allowSingle as per your use case
In your controller
//if you want to set extra params
yourStore.getProxy().setExtraParam("anyParam",anyValue);
// sync the store
yourStore.sync({success : function() {
yourGrid.setLoading(false);
.. },
scope : this // within the scope of the controller
});
You should be creating the model with a new id ( you can ignore it at the server side and use your own key generation , but it lets extjs4 for its internal purposes know that a new record has been created).
creating a model instance
var r = Ext.create('yourModel', { id: idGen++, propA : valA , ... });
insert to grid
store.insert(0,r);
var editPlugin = grid.getPlugin(editPluginId);
editPlugin.startEdit(0,1);
Once you receive a response back the id's can be update to their true value.
in the Store
reader :
{
type : 'json',
root : 'yourdata',
successProperty : 'success',
idProperty : 'id'
}
If you were to use the same grid for handling and editing then you could use the write event or the appropriate event
for more advanced handling in the Store
listeners :
{
write : function(store,operation, eOpts)
{
var insertedData = Ext.decode(operation.response.responseText);
.. do something
}
}
I would recommend using the mvc architecture of Extjs4
This is what I tried and it seems to work:
var store = Ext.create('Ext.data.Store', {
// destroy the store if the grid is destroyed
autoDestroy: true,
model: 'Plant',
proxy: {
type: 'ajax',
url: '/CellEditing/CellEditingGridServlet',
writer: {
type: 'json',
root: 'plantDetails'
}
}
handler : function(){
grid.getStore().sync();
But I am getting an additional parameter in the JSON at the server side:
"id": null
I don't have this id set in my model then where is this coming from? Is there some way to set some values to it rather than having a default null value?

Resources