Backbone.js collection get does not work - javascript

var sgt1 = Backbone.Collection.extend({
model: sgt2
});
var a = new sgt1();
a.add({attr1: 'asd'});
Ok, up to now it is works but:
a.get(0) returns undefined
and
a.at(0) returns an obj
Why does get return undefined?

a.get(0) fetches by ID. It is not the same as at which fetches by index position. Since your model does not yet have an ID, get would not work.

With get() you query the collection by the models id field and not by its index like with at(). Please refer to the documentation.

Related

Javascript / Parse: Follow wont return 'to' value

I am trying to get all of the users that are following the current user. From some reason Parse returns the username as undefined in the 'to' field but I am able to retrieve the user name from the 'from' field like so:
var query = new Parse.Query("Follow");
query.equalTo("to", Parse.User.current());
query.find({
success: function(users){
for (var i = 0; i < users.length; i++) {
console.log(users[i].get('from').get('username')) // returns current username
console.log(users[i].get('to').get('username')) / returns undefined
}
}
});
But those values do exist and there is a username. I am able to get the value using the fetch method but I am curious as to why this approach doesn't work. Thoughts?
From Doc, you're not getting the actual object, but the ref to that object:
Internally, the Parse framework will store the referred-to object in just one place, to maintain consistency. ......
And
By default, when fetching an object, related Parse.Objects are not
fetched. These objects' values cannot be retrieved until they have
been fetched like so:
// Here, post is something similar to your `users[i].get('to')`
var post = fetchedComment.get("parent");
// So you need to fetch it again to get its real object.
post.fetch({
success: function(post) {
var title = post.get("title");
}
});
So what you get from users[i].get('to') is a reference to that user object. You can either fetch it again.

Backbone collection.reset adds one incorrect model

I have a collection which is filtered through a search box. When a search/filter is performed, I get a result which is a collection. This collection is correct and contains the expected models from the search. When I use collection.reset(result) it adds a backbone collection which contains one model which has nothing to do with the result collection, nor does it contain anything but the standard collection backbone stuff.
The Collection
var Products = Backbone.Collection.extend({
model: Product,
url : '',
search : function(letters){
if(letters == "") return this;
var pattern = new RegExp(letters,"gi");
return new Products((this.filter(function(data) {
return pattern.test(data.get("title"));
})));
}
});
From the view:
search : function (ev){
var results = products.search($("#search").val());
console.log("result");
console.log(results);
this.collection.reset(results);
console.log("altered collection");
console.log(this.collection);
}
And an image showing what it contains at the different points of logging:
Again the filtered collection (after result) is 100% correct and what I expect it to be. The state of this.collection prior reset, is also correct. The only thing I do is this.collection.reset(result); and log this.collection again. I listen to the 'reset' event, and when it fires there is obviously no models to render and I get an error.
it looks like results is a Products collection. collection.reset() expects an array of models, not a collection.
Try this.collection.reset(results.models);

Backbone collection fetch imported incorrectly

I have a collection which is fetched from a REST endpoint, where it receives a JSON.
So to be completely clear:
var Products = Backbone.Collection.extend({
model: Product,
url : 'restendpoint',
customFilter: function(f){
var results = this.where(f);
return new TestCollection(results);
}
});
var products = new Products();
products.fetch();
If I log this, then I have the data. However, the length of the object (initial) is 0, but it has 6 models. I think this difference has something to do with what is wrong, without me knowing what is actually wrong.
Now, if I try to filter this:
products.customFilter({title: "MyTitle"});
That returns 0, even though I know there is one of that specific title.
Now the funky part. If I take the ENTIRE JSON and copy it, as in literally copy/paste it into the code like this:
var TestCollection = Backbone.Collection.extend({
customFilter: function(f){
var results = this.where(f);
return new TestCollection(results);
}
});
var testCollectionInstance = new TestCollection(COPY PASTED HUGE JSON DATA);
testCollectionInstance.customFilter({title: "MyTitle"});
Now that returns the 1 model which I was expecting. The difference when I log the two collections can be seen below. Is there some funky behaviour in the .fetch() I am unaware of?
Edit 2: It may also be of value that using the .fetch() I have no problems actually using the models in a view. It's only the filtering part which is funky.
Edit 3: Added the view. It may very well be that I just don't get the flow yet. Basically I had it all working when I only had to fetch() the data and send it to the view, however, the fetch was hardcoded into the render function, so this.fetch({success: send to template}); This may be wrong.
What I want to do is be able to filter the collection and send ANY collection to the render method and then render the template with that collection.
var ProductList = Backbone.View.extend({
el: '#page',
render: function(){
var that = this; /* save the reference to this for use in anonymous functions */
var template = _.template($('#product-list-template').html());
that.$el.html(template({ products: products.models }));
//before the fetch() call was here and then I rendered the template, however, I needed to get it out so I can update my collection and re-render with a new one (so it's not hard-coded to fetch so to speak)
},
events: {
'keyup #search' : 'search'
},
search : function (ev){
var letters = $("#search").val();
}
});
Edit: New image added to clearify the problem
It's a bit tricky, you need to understand how the console works.
Logging objects or arrays is not like logging primitive values like strings or numbers.
When you log an object to the console, you are logging the reference to that object in memory.
In the first log that object has no models but once the models are fetched the object gets updated (not what you have previously logged!) and now that same object has 6 models. It's the same object but the console prints the current value/properties.
To answer your question, IO is asynchronous. You need to wait for that objects to be fetched from the server. That's what events are for. fetch triggers a sync event. Model emits the sync when the fetch is completed.
So:
var Products = Backbone.Collection.extend({
model: Product,
url : 'restendpoint',
customFilter: function(f){
var results = this.where(f);
return new TestCollection(results);
}
});
var products = new Products();
products.fetch();
console.log(products.length); // 0
products.on('sync',function(){
console.log(products.length); // 6 or whatever
products.customFilter({title: 'MyTitle'});
})
It seems like a response to your ajax request hasn't been received yet by the time you run customFilter. You should be able to use the following to ensure that the request has finished.
var that = this;
this.fetch({
success: function () {
newCollection = that.customFilter({ title: 'foo' });
}
});

how to pass an id containing / in backbone.js

HI my basic model which fetches data from server is working perfect. I want to implement a search feature. When user enters any data the request goes to browser and desired model is returned.
var Book = Backbone.Model.extend({
urlRoot: '/books'
});
render: function(options) {
books = new Book({id:options.name});
books.fetch();
}
where
name = "search/"+dynamic_data;
Request URL that is being formed when i pass --> 'life' in variable dynamic_data
http://host/path/search%2Flife
Request URL that i want
http://host/path/search/life
How can I encode/escape my string to achieve the desired result. I have tried escape(), encodeURI(), encodeURIComponents
A workaround to solve this is create one more model with urlRoot as /books/search and pass just name . I don't think this is correct. Should I use this ?
According to your additionnal precisions stating that life is actually a book name...
It looks like Backbone is better integrated with RESTful API's. In REST, your urls should not contain verbs and to search books, you would do a GET /books/?name=life.
In that case, you would only have to define a Backbone.Collection like:
var BooksCollection = Backbone.Collection.extend({
model: Book,
url: '/books'
});
The to fetch books:
var books = new BooksCollection();
books.fetch({data : {name: 'life'}}); //GET /books/?name=life
If you really want your search operation to target /search/:name, you will have to check the Backbone.Collection api, but I think you will want to look at http://backbonejs.org/#Sync
You could override your collection's sync method to something like:
Backbone.Collection.extend({
...
sync: function (method, model, options) {
//for read operations, call the search url
if (method === 'read') {
options.url = '/search/' + options.data.name;
delete options.data.name;
}
//call the default sync implementation
return Backbone.Collection.prototype.sync.apply(this, arguments);
}
});
In this cased calling books.fetch({data : {name: 'life'}}); will result in GET /books/life.
Here's a fiddle that shows the example.
this would work:
books = new Book({id:options.name}, {url: options.name));
decodeURIComponent() will decode http://host/path/search%2Flife to http://host/path/search/life.

Reading all object values in StackMob

I've been using StackMob's fetch() function to retrieve all objects in my table, given by the fetch() method as a single model object. Each object has multiple attributes with corresponding values. I've then used JSON.stringify(model) to get this output:
{"0":{"attribute1":val1,"attribute2":"val2","attribute3":val3,"attribute4":"val4"},
"1":{"attribute1":val1,"attribute2":"val2","attribute3":val3,"attribute4":"val4"},
"2":{"attribute1":val1,"attribute2":"val2","attribute3":val3,"attribute4":"val4"}
...and so on.
How can I print out just each of those values?
StackMob has a get() function that can be used as such:
var a_book = new Book({ 'title': 'The Complete Calvin and Hobbes', 'author': 'Bill Watterson' });
console.debug(a_book.get('title')); //prints out "The Complete Calvin and Hobbes"
But I'm not sure how I would use it in my situation, where I'm retrieving all of the objects in my table, rather than creating a new object (as above).
since the stackmob js sdk is built on backbonejs you could declare a collection which can contain all the "rows" in your "table" and then iterate through the collection to perform whatever action you want to each item in your "table"
var MyModel = StackMob.Model.extend({
schemaName:'YOUR_SCHEMA_NAME'
});
var MyCollection= StackMob.Collection.extend({
model:MyModel
});
var myCollection = new MyCollection();
myCollection.fetch({async: true});
myCollection.each(function(item){
//do something with item, maybe print
});

Categories

Resources