I'm trying to understanding backbone code. I read this
http://addyosmani.com/blog/building-spas-jquerys-best-friends/
then I plan to change this
if (this._index === null){
$.ajax({
url: 'data/blog.json',
dataType: 'json',
data: {},
success: function(data) {
ws._data = data;
console.log(ws._data);
ws._blogs = new BlogCollection(data.rows);
console.log(ws._blogs);
ws._index = new IndexView({model: ws._blogs});
Backbone.history.loadUrl();
}
});
return this;
}
return this;
use collection fetch
if (this._index === null){
ws._data = new BlogCollection;
ws._data.fetch({success: function(data){console.log(data.models[0].attributes);}});
//ws._blogs = new BlogCollection(ws._data.rows);
//ws._index = new IndexView({model: ws._blogs});
Backbone.history.loadUrl();
}
with this collection
var BlogCollection = Backbone.Collection.extend({
model: Blog,
url : 'data/blog.json',
parse: function(response){
return response;
}
when I read the response from collection, it's give same value as using jquery ajax.
but when I use fetch in controller, why I have to access data.models[0].attributes); to get the same data return.
this is my json
{ "page":"1", "total": "5", "records": "25", "rows":
[
{
"title": "Classic Pop",
"author": "Michael Jackson Collection",
"image": "images/1.jpg",
"tags": ["xyz", "abc", "def"],
"slug" : "classic-pop",
"url": "http://www.localhost/news",
"intro": "hello test",
"content": "hello test, alfjldsajfldjsflja dljfldasjfa jfljdasfl jfldsjf jljdafl jl"
},
{
"title": "Modern Pop/R&B",
"author": "Bruno Mars and Others",
"image": "images/54.jpg",
"tags": ["test", "test2", "test3"],
"slug" : "modern-pop-rb",
"url": "http://www.localhost/news",
"intro": "hello test 2",
"content": "hello test, alfjldsajfldjsflja dljfldasjfa jfljdasfl jfldsjf jljdafl jl"
}
] }
how to make fetch works right??
When extending your Backbone Collection, you should define a parse function that returns an array of rows that represent the models contained in your collection.
In your case, it must be an array of data, with each object in the array representing your Blog model, so you need to return the rows property:
var BlogCollection = Backbone.Collection.extend({
model: Blog,
url : 'data/blog.json',
parse: function(response){
return response.rows;
}
});
Then if your model has a parse function, it will get the data for each object contained in the array, in case you need to do anything with the data before the model's attributes are set:
var Blog = Backbone.Model.extend({
//data will contain one of the items returned from the collection's 'parse' function.
parse: function(data){
return data;
}
});
This will ensure that the Backbone collection will properly create and populate the models represented in the collection with the data.
You will probably want to expose the other metadata (page, total, records) on the collection too, perhaps with a property that is also a Backbone.Model of page/total/records.
Related
I'm sure I'm missing something very basic. I'm setting up a collection of fetched objects
collection.fetch({reset: true})
based on a model that contains a 'defaults' property.
However, when I view the fetched collection in the console I have an extra model in it, which is set with the default attributes. Why is this happening? More importantly, how do I prevent it?
var diningApp = diningApp || {};
(function(){
"use strict";
diningApp.MenuItem = Backbone.Model.extend({
defaults: {
service_unit: null,
course: null,
formal_name: null,
meal: null,
portion_size: null,
service_unit_id: null
}
});
var MenuCollection = Backbone.Collection.extend({
model: diningApp.MenuItem,
url: '/api/dining/get_menus',
parse: function(response){
return response.menu_items;
}
});
diningApp.menuCollection = new MenuCollection();
diningApp.menuCollection.fetch({reset: true});
})();
Here is a portion of the JSON response from the server:
{
"status": "ok",
"menu_items": [
{
"service_unit": "Faculty House",
"course": "Entrees",
"formal_name": "Local CF Fried Eggs GF",
"meal": "BREAKFAST",
"portion_size": "1 Egg",
"service_unit_id": 0
},
{
"service_unit": "Faculty House",
"course": "Entrees",
"formal_name": "CageFree Scrambled Eggs GF",
"meal": "BREAKFAST",
"portion_size": "2 eggs",
"service_unit_id": 0
}]
}
And here's the resulting collection in the console:
If you dig a bit into Backone's source code to check what happens when you reset a collection, you'll end looking at Collection.set. The lines of interest to your problem are :
// Turn bare objects into model references,
// and prevent invalid models from being added.
for (i = 0, l = models.length; i < l; i++) {
attrs = models[i] || {};
// ...
This means that each falsy (false, null, etc.) item in the array is converted to an empty object before being cast into a model and receiving default values.
Either
modify your server response to remove falsy values
or alter your parse method to clean up you array
parse: function(response){
return _.compact(response.menu_items);
}
I'm trying to merge two objects into a single multidimensional object for use in Angularjs controller by the 'unique_id'. (Note I also have Underscore Js added in).
Object #1 example:
[
{ "unique_id": "001", "title": "Putting Green Challenge - Motion Depends on Force and Mass" },
{ "unique_id": "002", "title": "Molecules to Organisms: Frog Life Cycle" }
]
Object #2 example (has MANY more rows than object 1..):
[
{
"ab_id": "76153F02-29F3-11D8-95EA-951BF95D9AEF",
"unique_id": "001",
"title": "How Speed Relates to Energy",
"state": "NY",
"document_title": "Core Curriculum",
"grade_code": "K-4",
"grade_descr": "Elementary",
"state_id": "1.S2.3a",
"state_text": "Use appropriate \"inquiry and process skills\" to collect data"
},
{
"ab_id": "7980A762-29F3-11D8-BD14-861D7EA8D134",
"unique_id": "001",
"title": "How Speed Relates to Energy",
"state": "NY",
"document_title": "Core Curriculum",
"grade_code": "5-8",
"grade_descr": "Intermediate",
"state_id": "1.S3.2d",
"state_text": "formulate and defend explanations and conclusions as they relate to scientific phenomena"
}
]
My Controller:
abApp.controller("abEE", function(abService, $http, $scope, $q, _) {
var abApp = this;
$scope.abData = $http.get('/data/ab_activities.json', {
cache: false
});
$scope.eeData = $http.get('/activities/eedata', {
cache: false
});
$q.all([$scope.eeData, $scope.abData]).then(function(values) {
var val = ??? This is where I want to merge the objects into one big multidimensional object..
});
Here is the output of console.dir(values);
0 Object { data=[28], status=200, config={...}, more...}
1 Object { data=[743], status=200, config={...}, more...}
This is the desired output I'd like to try and get:
[
{ "unique_id": "001", "title": "Putting Green Challenge - Motion Depends on Force and Mass", "alignments": [{"ab_id": "76153F02-29F3-11D8-95EA-951BF95D9AEF","unique_id": "001","title": "How Speed Relates to Energy",...}, {"ab_id": "7980A762-29F3-11D8-BD14-861D7EA8D134", "unique_id": "001", "title": "How Speed Relates to Energy",...}]
]
Edit
after you updated the question, i created this plunker
hopes it's what you meant
To merge all objects by unique_id
var unions = {};
$q.all([$scope.eeData, $scope.abData]).then(function(values)
{
for (var i = 0; i< values.length; i++)
{
var value = values[i];
if (!unions[value.unique_id])
{
unions[value.unique_id] = {};
}
angular.extend(unions[value.unique_id], value);
}
});
// Do somthing with 'unions'
...
If you could switch to use lodash instead of underscore, it can be achieved like this:
var val = _.values(_.merge(_.indexBy(values[0].data, 'unique_id'), _.indexBy(values[1].data, 'unique_id')));
The underscore doesn't have _.merge(), you have to loop through each property without it.
I don't think angular or underscore have this kind of functionality. I would do something like the following pseudo-code:
tempObject = {}
for object in objectArray
if tempObject[object.unique_id] isnt undefined
tempObject[object.unique_id] = object
else angular.extend(tempObject[object.unique_id], object) // or the other way around depending on your preference
resultingArray = []
for object, key of tempObject
resultingArray.push(object)
You will have to run the for object in objectArray for both the returned arrays but that should work and is probably more efficient than most merge algorithms as at most it will loop through each returned arrays twice.
how to search array of object in backbone js.The collection contain persons model.
[{
name: "John",
age: "18",
likes: {
food: "pizza",
drinks: "something",
}
},
......
]
how can i get persons who likes something.
i did try collection.where({likes :{food : "pizza"}});
Since your food property is in an object on the Person's attributes, using where (which by default just looks at the flat attributes) isn't going to work. You can use the filter method to apply a truth test to all of the items in your collection and just get the ones that pass.
In the code you posted, it doesn't look like you have a Backbone Collection proper, just a regular array of objects.
Since Underscore is on the page, you can use it to help filter through your list.
var people = [
{
name: "John",
age: "18",
likes: {
food: "pizza",
drinks: "something",
}
},
......
];
var likesPizza = _.filter(people, function(person) {
return person.likes.food === "pizza";
});
If it is in fact a Backbone Collection, you can use
this.collection.filter(people, function(person) {
return person.get('likes').food === "pizza";
});
What is the root property value if I get a Json like that:
{
"status": {
"status": 0,
"msg": "Ok",
"protocolversion": "extjs.json"
},
"value": {
"table": [
[
"admin",
"Administrator",
""
],
[
"test",
"Test",
""
]
],
"total": 2
}
}
The data will be displayed in a gridpanel, 1 row is admin, 1 row is test, etc.
Tried:
value, value.table
How to get this to work?
value.table is correct for the root property, but you are using a json format that I don't think Ext is set up to handle by default. It has a reader for json that is used for an array of objects, not for an nested arrays of field values with no object mapping information.
If you have to use that format, you will either need to create your own readers/writers or just use Ext.Ajax.request(), and in the callback, parse the nested array into objects. Something like:
Ext.Ajax.request({
url: 'path.com/to/content',
success: function (response, operation) {
var data = Ext.JSON.decode(response.responseText);
var fields = data.value.table;
var records = [];
Ext.Array.each(fields, function (fieldArray, fieldIndex) {
Ext.Array.each(fieldArray, function(fieldValue, valueIndex) {
//Create record object if it doesn't exist
var record = records[valueIndex] || {};
//Create a switch statement based on the array index to set fields
switch(fieldIndex) {
case 0:
record.User_id = fieldValue;
break;
case 1:
record.Username = fieldValue;
break;
}
});
});
//Add the objects to the empty store
store.add(records);
}
});
That's not a production solution by any means since it doesn't handle that empty string at the end of your list or the case that you get a jagged array of arrays per field which I can't imagine what to do with. If it's within your control or influence, I would suggest using a format more like what Ext suggests so you can use the built in json proxy/reader/writer or go crazy with it and implement ext's remote procedure call format:
{
"success": true,
"message": "Success",
"data": [
{
"User_id": "admin",
"Username": "Administrator"
}, {
"User_id": "admin",
"Username": "Administrator"
}
]
}
In above example "value" is root property. But for JSON reader it's a property name (or a dot-separated list of property names if the root is nested).
so you can assign into your field you need following.
fields:['table.admin','table.test']
I'm sure I make one of these Backbone newbie mistakes but after a hour of searching around I didn't found a solution.
Here's the problem: When I try to get a filtered model from my collection theres a type error "productCollection.getProductByName("M020012").toJSON is not a function".
But if I change the filter method to a simple "return this.at(0)" I get a valid model.
Why is that and what is the solution?
Here's the JSFiddle
var products = [{
"name": "M020013",
"gender": "M",
"pictures": [{
"picture": {}}]},
{
"name": "M020012",
"gender": "M",
"pictures": [{
"picture": {}}]},
{
"name": "M020011",
"gender": "M",
"pictures": [{
"picture": {}}]}
];
var Product = Backbone.Model.extend({});
var ProductCollection = Backbone.Collection.extend({
model: Product,
getProductByName: function(productName) {
//return this.at(0);
return this.filter(
function(product) {
return product.get('name') === productName;
});
}
});
var productCollection = new ProductCollection();
productCollection.on('reset', function() {
console.log('reset');
console.log(productCollection.getProductByName('M020012'));
console.log(productCollection.getProductByName('M020012').toJSON());
});
productCollection.reset(products);
It's because filter returns an array of models. And an Array in javascript does not have a toJSON function.
Since you want to return a model instead of an array, then you can use the find in place of filter. The find method returns the first model that matches the criteria
Here's what the code would look like:
getProductByName: function(productName) {
return this.find(function(production) {
return production.get('name') === productName;
});
}