Dojo JsonRestStore with array not at root-level of JSON response - javascript

Is there a way to configure a JsonRestStore to work with an existing web service that returns an array of objects which is not at the root-level of the JSON response?
My JSON response is currently similar to this:
{
message: "",
success: true,
data: [
{ name: "Bugs Bunny", id: 1 },
{ name: "Daffy Duck", id: 2 }
],
total: 2
}
I need to tell the JsonRestStore that it will find the rows under "data", but I can't see a way to do this from looking at the documentation. Schema seems like a possibility but I can't make sense of it through the docs (or what I find in Google).
My web services return data in a format expected by stores in Ext JS, but I can't refactor years worth of web services now (dealing with pagination via HTTP headers instead of query string values will probably be fun, too, but that's a problem for another day).
Thanks.

While it's only barely called out in the API docs, there is an internal method in dojox/data/JsonRestStore named _processResults that happens to be easily overridable for this purpose. It receives the data returned by the service and the original Deferred from the request, and is expected to return an object containing items and totalCount.
Based on your data above, something like this ought to work:
var CustomRestStore = declare(JsonRestStore, {
_processResults: function (results) {
return {
items: results.data,
totalCount: results.total
};
}
});

The idea with dojo/store is that reference stores are provided, but they are intended to be customized to match whatever data format you want. For example, https://github.com/sitepen/dojo-smore has a few additional stores (e.g. one that handles Csv data). These stores provide good examples for how to handle data that is offered under a different structure.
There's also the new dstore project, http://dstorejs.io/ , which is going to eventually replace dojo/store in Dojo 2, but works today against Dojo 1.x. This might be easier for creating a custom store to match your data structure.

Related

SailsJS MongoDB store and access Array of Object

I'm trying to make a real-time vote application using SailsJS, and am currently having troubles with MongoDB. I am completely new to this, and have been just using SailsJS mimic easy calls to access MongoDB.
module.exports = {
attributes: {
selectOptions:{
type: 'Object'
},
question:{
type:'string',
required: true
},
password:{
type:'string',
required: true
}
}
};
The above code is for the model that I have, and I am the selectOptions should have an array of objects, like [{id: 1,result: 0},{id:2,result 0},...] and would like to know how to do this, as I cannot seem to find any documentation about the array of objects. Only thing I found was something about collection, or making another model and link that to the original model, but when i tried it, sails gave me some foreign key error that I have never faced before. I really really appreciate your time, and look forward for the response.
P.S - I tried making the array into either JSON or Object or nothing(Like not put any type under selectOptions) and made change to the model as well to see if it works, but both JSON and Object didn't work, but selectOptions did. However, I think it was returning a string, as it the length was longer than what the array was supposed to be.

Deep-wrapping of JSON response objects in Ember Objects

I am currently working on an Ember project where I fetch a complex JSON response in a Route's model function. In the corresponding template, I display attributes of the response. For some of them, there are certain actions available which lead to changes on this model.
I want these changes to be directly reflected in the UI using Ember's binding. Unfortunately, while accessing a top-level response property in the ObjectController with this.get('attributeFromJson') works well, trying the same (or a set) on one of the child properties doesn't work.
I have produced the following JSFiddle to demonstrate the problem: http://jsfiddle.net/KkD6U/
My understanding is that I would need to convert the response into a Ember.Object manually in order to benefit from its Ember.Observable mixin.
My question is: is there any plain Ember way to automatically "deep-wrap" a whole JSON response into a structure of Ember.Object to use get and set on the whole response? What would be the plain Ember way to do this?
Update:
In the meantime, I built a trivial function to convert plain JS objects to Ember objects, see jsFiddle here: http://jsfiddle.net/5vEcL/1/
Does it look feasible?
My understanding is that I would need to convert the response into a Ember.Object manually in order to benefit from its Ember.Observable mixin.
Basically yes, if you would wrap your child objects in a Ember.Object.create(...) it would work with ember's binding mechanism:
...
anArray: [
Ember.Object.create({
id: '1',
anotherAttribute: '123'
}),
Ember.Object.create({
id: '2',
anotherAttribute: '456'
})
]
...
See here your modified jsfiddle of the example above: http://jsfiddle.net/ZZFkA/
Hope it helps.

BackboneJS collection.reset() vs collection.fetch()

I have read and read the docs on these two methods, but for the life of me cannot work out why you might use one over the other?
Could someone just give me a basic code situation where one would be application and the other wouldn't.
reset sets the collection with an array of models that you specify:
collection.reset( [ { name: "model1" }, { name: "model2" } ] );
fetch retrieves the collection data from the server, using the URL you've specified for the collection.
collection.fetch( { url: someUrl, success: function(collection) {
// collection has values from someUrl
} } );
Here's a Fiddle illustrating the difference.
We're assuming here that you've read the documentation, else it'l be a little confusing here.
If you look at documentation of fetch and reset, what it says is, suppose you have specified the url property of the collection - which might be pointing to some server code, and should return a json array of models, and you want the collection to be filled with the models being returned, you will use fetch.
For example you have the following json being returned from the server on the collection url:
[{
id : 1,
name : "a"
}, {
id : 2,
name : "b"
}, {
id : 3,
name : "c"
}]
Which will create 3 models in your collection after successful fetch. If you hunt for the code of collection fetch here you will see that fetch will get the response and internally will call either reset or add based on options specified.
So, coming back to discussion, reset assumes that we already have json of models, which we want to be stored in collection, we will pass it as a parameter to it. In your life, ever if you want to update the collection and you already have the models on client side, then you don't need to use fetch, reset will do your job.
Hence, if you want to the same json to be filled in the collection with the help of reset you can do something like this:
var _self = this;
$.getJSON("url", function(response) {
_self.reset(response); // assuming response returns the same json as above
});
Well, this is not a practice to be followed, for this scenario fetch is better, its just used for example.
Another example of reset is on the documentation page.
Hope it gives a little bit of idea and makes your life better :)
reset() is used for replacing collection with new array. For example:
#collection.reset(#full_collection.models)
would load #full_collections models, however
#collection.reset()
would return empty collection.
And fetch() function returns default collection of model

How to read two different objects returned via the same REST URL using Backbone?

I have a REST URL, say
/users/<user_id>/entities
which returns 2 objects within it:
{
"players":
{
"test_player2":
{
"_id": "test_player2",
"user": "f07590567f3d3570b4f35b4fd79f18b3"
},
"test_playerX":
{
"_id": "test_player2",
"user": "f07590567f3d3570b4f35b4fd79f18b3"
}
},
"games":
{
"game1" :{},
"game2" :{},
}
}
How do I design my Backbone Objects to use this data?
Requirement:
I want two different Backbone objects: Player, and Game, which should be populated via the same url (mentioned above).
PS: Is it even a correct practice to design this kind of REST URL?
Is it even a correct practice to design this kind of REST URL?
No, it's not a correct practice. In REST, a single URL is supposed to represent a single resource. Therefore, your /users/<user_id>/entities URL should be /users/<user_id>/players and only return a list of players, and /users/<user_id>/games and only return a list of games.
However, there may be a time when you have no control over what the API returns. Generally, this is the case for nested objects (you may be able to do it with what you have, but ideally, you'll want to change your API):
{
"players":
{
"id": 1,
"games":
{
"id": 1745,
"title": "Team Fortress 2"
}
}
}
In which case, you would use the model's parse function, with something like:
parse: function(response)
{
// Make sure "games" actually exists and is an array to make a collection from
if(_.isArray(response.games))
{
// Backbone will automatically make a collection of models from an array
// Use {parse: true} if you want the receiving collection to parse as if a fetch had been done
this.games = new GamesCollection(response.games,{parse: true});
}
}
By overriding parse and using {parse:true}, you can build out your models pretty much indefinitely. It's not necessarily ideal to do it that way (the idea is that each collection is responsible for its own models), but it works for those cases when you get compound objects and can't change what the API returns.

Persisting & loading metadata in a backbone.js collection

I have a situation using backbone.js where I have a collection of models, and some additional information about the models. For example, imagine that I'm returning a list of amounts: they have a quantity associated with each model. Assume now that the unit for each of the amounts is always the same: say quarts. Then the json object I get back from my service might be something like:
{
dataPoints: [
{quantity: 5 },
{quantity: 10 },
...
],
unit : quarts
}
Now backbone collections have no real mechanism for natively associating this meta-data with the collection, but it was suggested to me in this question: Setting attributes on a collection - backbone js that I can extend the collection with a .meta(property, [value]) style function - which is a great solution. However, naturally it follows that we'd like to be able to cleanly retrieve this data from a json response like the one we have above.
Backbone.js gives us the parse(response) function, which allows us to specify where to extract the collection's list of models from in combination with the url attribute. There is no way that I'm aware of, however, to make a more intelligent function without overloading fetch() which would remove the partial functionality that is already available.
My question is this: is there a better option than overloading fetch() (and trying it to call it's superclass implementation) to achieve what I want to achieve?
Thanks
Personally, I would wrap the Collection inside another Model, and then override parse, like so:
var DataPointsCollection = Backbone.Collection.extend({ /* etc etc */ });
var CollectionContainer = Backbone.Model.extend({
defaults: {
dataPoints: new DataPointsCollection(),
unit: "quarts"
},
parse: function(obj) {
// update the inner collection
this.get("dataPoints").refresh(obj.dataPoints);
// this mightn't be necessary
delete obj.dataPoints;
return obj;
}
});
The Collection.refresh() call updates the model with new values. Passing in a custom meta value to the Collection as previously suggested might stop you from being able to bind to those meta values.
This meta data does not belong on the collection. It belongs in the name or some other descriptor of the code. Your code should declaratively know that the collection it has is only full of quartz elements. It already does since the url points to quartz elements.
var quartzCollection = new FooCollection();
quartzCollection.url = quartzurl;
quartzCollection.fetch();
If you really need to get this data why don't you just call
_.uniq(quartzCollecion.pluck("unit"))[0];

Categories