1

Can someone tell me how to re fetch a Backbone collection after calling collection's create function when I create a new model?

When I call fetch on my collection after creating new model, sometimes I'm getting that model and sometimes not.

My problem is when I create a new model in my collection, I'm not getting the id back of my model and then I can't update it immediately, I need to refresh the page and then I got the id of the created model.

I tried with listenTo but I can't use it because I need to send more collections to one function.

And that my view for my bootstrap modal, on save I'm creating my model it persists to database and I'm getting all attributes in my console when I create it except models id.

Backbone view:

app.types.EditView = Backbone.View.extend({

    tagName: "div",

    $container: $('#containerEdit'),
    template: _.template($('#itemEdit-template').html()),

    events: 
    {
            "click .save": "save",
    },

    initialize: function(options)
    {   
            this.options = options;

            this.$container.html(this.render());

            this.start();
            this.end();
    },

    render: function() 
    {
            this.$el.html(this.template());
            return this.$el;
    },

    save: function() 
    {
            console.log("save");
            $('#openModal').modal('hide');
            var dan = this.model.dan_u_tjednu_usera.datum;
            var mjesec = this.model.dan_u_tjednu_usera.mjesecBrojevi;
            var godina = this.model.dan_u_tjednu_usera.godina;
            var start = $("#start").val();
            var end = $("#end").val();
            var user_id = this.model.user.id;

            this.model.shifts.create({day: dan, month: mjesec, year: godina, time_from: start, time_to: end, user_id: user_id});
            this.options.model.el.html($("<td href='#openModal' width='25%' align='center' class='list-group test' scope='row'>" + start + " - " + end + " " + "Admin" + "</td>"));
            this.model.shifts.fetch({sync: true});
            console.log("test", this.model.shifts);

    }

Here you can see that in my response im not getting the id attribute, on create.

enter image description here

And here you can see when i click on my cell i log my collection and i have not the id attribute of the created model here. And im not getting the id attribute it too when i log this.model

enter image description here

lorenos
  • 115
  • 2
  • 12

2 Answers2

1

This is because the request sent to the server when you call Collection.create is asynchronous, the Javascript code will continue to execute before the server receives and responds to the request.

If you want to have the Model updated with the ID coming back from the server, you can specify {wait: true} in the Collection.create call. This will mean that the Collection will not have the Model added straight away, but instead only when the server responds (successfully).

In this case you should not run the fetch immediately afterwards, as it will also need to wait for the create operation to complete. You should setup any following actions to trigger when the create operation has completed. Here is an example:

var model = collection.create({field: 'abc'}, {wait: true});
model.once('sync', function() { window.alert(model.id); });
mikeapr4
  • 2,830
  • 16
  • 24
  • I'm not getting the id of created model, `window.alert` not getting fired i tried `console.log` and neither fired. When i create model i got the model in my database with my id, but when i console log my collection i get the model without id. – lorenos Oct 28 '16 at 13:39
  • Does your service call return the new attributes? – mikeapr4 Oct 28 '16 at 14:23
  • Yes im getting the new attributes in my console but without the id of the new model. When i fetch two times im getting it, but i won't fetch two times i wanma fetch it once or do it with sync method if its possible. – lorenos Oct 28 '16 at 14:32
  • Looks like you'll need to fix the service call so that it returns the ID for the new model. – mikeapr4 Oct 28 '16 at 15:13
  • Whats a service call? – lorenos Oct 28 '16 at 15:56
  • by Service Call, I mean the Server Side API (likely REST) which performs the database action. If for example you were working in Java on the server-side, something like this might help: http://stackoverflow.com/a/7635400/1084004 – mikeapr4 Oct 28 '16 at 18:04
1

Backbone's create

Convenience to create a new instance of a model within a collection. Equivalent to instantiating a model with a hash of attributes, saving the model to the server, and adding the model to the set after being successfully created.

There's no need to fetch a collection after a create, the model id and any other field are automatically merged within its attributes hash.

Fetch after model creation

While mikeapr4 is not wrong, his example could be improved.

The { wait: true } is unnecessary if the only problem comes from the fetch, not from the model already being inside the collection.

Also, once should be avoided as it's the "old" way, and instead listenToOnce should be used. See Difference between ListenTo and on.

If you really want to fetch once a model is created, using events is overkill here, and instead, using the success callback is best:

save: function() {
    // ..snip...
    this.model.shifts.create({ /* ...snip... */ }, {
        context: this,
        success: this.onModelCreated
    });
},

onModelCreated: function() {
    // the model is now created and its attributes are up-to-date
    this.model.shifts.fetch();
}

Other notes on your code

There are no sync option in Backbone. Only a "sync" event and a sync function.


Avoid using the global jQuery selector (like $('.class-name')) and instead, whenever the element is within the view's element, use this.$('.class-name').

Also, cache the jQuery element to avoid the costly search of the find method.

Like $("#start") could be cache and reused. Only reset the cached elements when re-rendering.


The Backbone .render function should return this by convention.

Then, your rendering call should look like:

this.$container.html(this.render().el); // el is enough
Community
  • 1
  • 1
Emile Bergeron
  • 17,074
  • 5
  • 83
  • 129
  • good point about `listenToOnce`, it is preferable, however the suggestion to use `{wait: true}` is valid, it means that the model will not be added to the collection until it is valid (i.e. has an ID), this should be part of the fix in case there are other parts of the same application using the collection and potentially reacting to an 'add' event from it. – mikeapr4 Oct 28 '16 at 18:10
  • @mikeapr4 If a certain validation is only available from the server-side, **remove the model on error**. It makes your app feels **more responsive** as there are no wait times between action. It's like [interpolation in multiplayer](http://www.gabrielgambetta.com/fpm3.html) games. – Emile Bergeron Oct 28 '16 at 18:22
  • Judging from the question, it appears the application behaves incorrectly for models without IDs, therefore better to wait until they are ready in order to use them. An example might be where the model is subsequently rendered with a link including it's ID for a further action (edit/delete etc). But we're both making assumptions about how this application works. – mikeapr4 Oct 28 '16 at 18:55
  • 1
    @mikeapr4 I agree, `wait` could have its use, but here it's only assumptions. I personally never had to use it yet. – Emile Bergeron Oct 28 '16 at 19:00
  • @mikeapr4 I changed the phrasing to demonstrate how I'm assuming the problem is from the fetch, and not from the collection being populated too soon. – Emile Bergeron Oct 28 '16 at 19:02
  • I'm sorry for not answering but success callback is not working, it won't even fetch my collection when i create a new model, because in network i can see it's not fetching again. In my database it creates fine but when i click on a new created model im getting all his attributes except his attribute id. Don't know how to make that when i create a new model and i click on that model in this situation on a cell with hours i wanna get all models attributes with attribute id. – lorenos Oct 31 '16 at 14:42
  • I have updated my question i have put two pictures so you can see what i mean. – lorenos Oct 31 '16 at 14:57
  • @lorenos your API must handle returning a new ID on POST (if no error occurred). If it doesn't, it's a problem with the API not being standard. – Emile Bergeron Oct 31 '16 at 15:00
  • @Emile Bergeron im not getting any errors on POST, so i should see in my network response the id attribute of new created model when i create it? – lorenos Oct 31 '16 at 15:25
  • @lorenos When you post to the API, the server should know it's a create request, it should create a new entry and returns that entry data with a new ID. So yes, you should see the ID along other data in the network response. – Emile Bergeron Oct 31 '16 at 15:39
  • @Emile Bergeron but im sending just the attributes i want to save and id is sets up alone in database, and the success callback don't works for me :( don't know how to solve that. – lorenos Oct 31 '16 at 15:43
  • @lorenos that's not a frontend problem, it looks like it's a backend problem. You should ask a new question about creating new entries with your backend and returning the ID. – Emile Bergeron Oct 31 '16 at 15:57