Backbone sync on collection add - backbone.js

I'm adding an item to my backbone collection like this:
item = existingItem.clone()
myCollection.add(item)
I have overwritten sync in MyCollection like this:
sync: function() {
console.log('sync is called')
}
however it seems that sync does not get called after the add - which executes successfully and fires an 'add' event. Am I missing something? or is this the correct behavior?

What you want is myCollection.create(item).
Check the Backbone Collection.create() doc

Collection.create returns the model, but in some cases you might need access to the xhr object. In that case you can do:
// add the model to the collection first
// so that model.url() will reference the collection's URL
myCollection.add(myModel)
// now save. this will trigger a POST to the collection URL
// save() returns the xhr so we can attach .done/.fail handlers
myModel.save()
.done(function(res) {
console.log('it worked')
})
.fail(function(err) {
console.log('it failed')
// might be a good idea to remove the model from the collection
// since it's not on the server
myCollection.remove(myModel)
})

Related

How to specify filtered Backbone collection for Marionette view

I have a Marionette composite view that displays a collection, which I set in my Application start handler:
App.on('start', function() {
Backbone.history.start({pushState: true});
// I load up this.appsCollection in my before:start handler
var tblView = new this.appsTableView({
collection: this.appsCollection
});
this.regions.main.show(tblView);
});
This works as expected, displaying my entire collection. In my models, I have a state field, and I want to display only models with state 0. I tried:
collection: this.appsCollection.where({state: 0})
but that doesn't work. I actually want to display states in 0 and 1, but I'm trying to just display state in 0 for right now.
What am I missing?
The problem probably resides in that .where() doesn't return a collection, but an array. http://backbonejs.org/#Collection-where This was supposedly to maintain compatibility with underscore.
If you change the line to:
collection: new Backbone.Collection( this.appsCollection.where( { state: 0 } ))
Does that help?
I was able to override the filter method in my Marionette CompositeView:
http://marionettejs.com/docs/v2.4.3/marionette.collectionview.html#collectionviews-filter

Backbone Marionette: How to use preventDestroy: true

For some reason, I can't get preventDestroy: true to work.
In my example, the loading view is removed, when the applicationsListView is showing - even though I pass in preventDestroy true.
var loadingView = new App.Common.Loading.View();
App.layout.mainRegion.show(loadingView);
// Fetch the applications
var fetchingApplications = App.request('application:entities');
$.when(fetchingApplications).done(function(applications) {
var applicationsListView = new List.Applications({
collection: applications
});
App.layout.mainRegion.show(applicationsListView, { preventDestroy: true });
});
It is removed from region but not destroyed.
When you pass preventDestroy : true, it means that marionette doesn't itself call destroy method and event on previous view. Destroy method provides ubinding events and calls destroy on subviews and so on (https://github.com/marionettejs/backbone.marionette/blob/master/docs/marionette.view.md#view-destroy).
But call show with preventDestroy : true still clear innerHTML and put new view in region (look at attachHtml method in backbone.marionette/src/marionette.region.js).
It can be helpfull if you reuse your existing loading view.

How to call fetch method of Backbone Collection passing Id

I want to fire fetch method on Backbone Collection which would pass an Id parameter similar to what happens in Model.fetch(id)
E.g.
var someFoo= new Foo({id: '1234'});// Where Foo is a Backbone Model
someFoo.fetch();
My Backbone collection:-
var tasks = backbone.Collection.extend({
model: taskModel,
url: '/MyController/GetTasks',
initialize: function () {
return this;
}
});
In my View when I try to fetch data:-
var _dummyId = 10; //
// Tried approach 1 && It calls an api without any `id` parameter, so I get 500 (Internal Server Error).
this.collection.fetch(_dummyId);
// Tried approach 2 && which fires API call passing Id, but just after that
// I am getting error as below:- Uncaught TypeError: object is not a function
this.collection.fetch({
data: {
id: _dummyId
}
});
Found it very late : To cut short the above story I want something like Get /collection/id in backbone.
Thank you for your answers, finally I got the solution from Backbone.js collection options.
Apologies that I couldn't explain the question properly while for same requirement others have done brilliantly and smartly.
Solution : I can have something like :-
var Messages = Backbone.Collection.extend({
initialize: function(models, options) {
this.id = options.id;
},
url: function() {
return '/messages/' + this.id;
},
model: Message,
});
var collection = new Messages([], { id: 2 });
collection.fetch();
Thanks to nrabinowitz. Link to the Answer
As mentioned by Matt Ball, the question doesn't make sense: either you call fetch() on a Collection to retrieve all the Models from the Server, or you call fetch() on a Model with an ID to retrieve only this one.
Now, if for some reason you'd need to pass extra parameters to a Collection.fetch() (such as paging information), you could always add a 'data' key in your options object, and it may happen that one of this key be an id (+add option to add this fetched model rather than replace the collection with just one model)... but that would be a very round-about way of fetching a model. The expected way is to create a new Model with the id and fetch it:
this.collection = new taskCollection();
newTask = this.collection.add({id: 15002});
newTask.fetch();
In your code however, I don't see where the ID is coming from, so I am wondering what did you expect to be in the 'ID' parameter that you wanted the collection.fetch() to send?

Backbone.js error - Uncaught TypeError: Object [object Object] has no method 'set'

My Code:
I am new to Backbone.js and trying to build an app with Backbone.js and PHP. When I am trying to call add in the router, I am getting error:
Uncaught TypeError: Object [object Object] has no method 'set'.
Please help me to find my mistake.
Thanks.
// Models
window.Users = Backbone.Model.extend({
urlRoot:"./bb-api/users",
defaults:{
"id":null,
"name":"",
"email":"",
"designation":""
}
});
window.UsersCollection = Backbone.Collection.extend({
model:Users,
url:"./bb-api/users"
});
// Views
window.AddUserView = Backbone.View.extend({
template:_.template($('#new-user-tpl').html()),
initialize:function(){
this.model.bind("click", this.render, this);
},
render:function(){
$(this.el).html(this.template(this.model.toJSON()));
return this;
},
events:{
"click .add":"saveUser"
},
saveUser:function(){ alert('saveUser');
this.model.set({
name:$("#name").val(),
email:$("#email").val(),
designation:$("#designation").val()
});
if(this.model.isNew()){
this.model.create(this.model);
}
return false;
}
});
// Router
var AppRouter = Backbone.Router.extend({
routes:{
"":"welcome",
"users":"list",
"users/:id":"userDetails",
"add":"addUser"
},
addUser:function(){
this.addUserModel = new UsersCollection();
this.addUserView = new AddUserView({model:this.addUserModel});
$('#content').html(this.addUserView.render().el);
}
});
var app = new AppRouter();
Backbone.history.start();
As suggested in the comments, the problem starts here here:
this.addUserModel = new UsersCollection();
this.addUserView = new AddUserView({model:this.addUserModel});
and finishes here:
saveUser:function(){ alert('saveUser');
this.model.set({
By passing a collection in place of a model you create confusion, and as a result later in the saveUser function you try to call a Backbone.Model method (set) on a Backbone.Collection instance.
Note: As of version 1.0.0 Backbone.Collection now has a set method. In previous versions, such as the one used by the question's author, that method was instead called update.
There are several steps you can take to clarify this code. For starters, I would rename your model and collection classes so that it's clear that the model is the singular form and the collection is the plural form:
window.Users => window.User
window.UsersCollection => window.Users
Next, I would create a new User model, instead of a Users collection, and pass that to your view:
this.addUserModel = new User();
this.addUserView = new AddUserView({model:this.addUserModel});
Finally, I'd remove these lines:
if(this.model.isNew()){
this.model.create(this.model);
}
For one thing, the model will always be new (as you just created it before passing it in), but more importantly you don't need to call the Collection's create method because that method creates a new model, when you already have one created. Perhaps what you should add instead is :
this.model.save();
if your intent is to save the model to your server.
Since you already specified a urlRoot for the model, that should be all you need to create a new model, pass it to your view, have your view fill in its attributes based on DOM elements, and finally save that model's attributes to your server.
I think you are facing problem with object scope. When event fired it send to event object to that function. Just try this it may work
Declare global variable with the current view inside the initialize
initialize : function(){ self = this; }
then change this to self,
saveUser:function(){ alert('saveUser');
self.model.set({
name:$("#name").val(),
email:$("#email").val(),
designation:$("#designation").val()
});
if(self.model.isNew()){
self.model.create(this.model);
}
return false;
}

adding a model to a relational-model's collection in an ajax event

I have a recipe model, and a recipe has an ingredientlist collection which stores a bunch of ingredients.
When I add an ingredient to the ingredient list from a form submit, I have to get an 'id' from the server, so I do an ajax request, get the id, and am trying to then add the ingredient to the model.
In my ingredientlist.view, I have
initialize: function(){
this.recipe = this.model;
},
get_ingredient: function(ingredient){
var ingredient_id = new MyApp.Models.Ingredient;
ingredient.url='/ingredients/?ing='+encodeURIComponent(ingredient_array[i]);
ingredient.fetch({
success: function() {
this.recipe('add:ingredients', function(ingredient,ingredientlist){
});
},
error: function() {
new Error({ message: "adding ingredient" });
}
});
}
I didn't include the function which triggers the 'get_ingredient', because it I am getting the ajax fine, so the problem isn't in triggering the 'get_ingredient'.
I get the errorUncaught TypeError: Property 'recipe' of object [object DOMWindow] is not a function
using the existing code.
what is the best way to accomplish something like this?
First of All i'm a newbie too with backbone.js!
So my thoughts is :
U need to bind your get_ingredient in your View : look bind to trigger your functions!
Try to pass the Context (this) to "get_ingredients"
This is just my 5 cents

Resources