Backbone partial view not rendering the latest model
Asked Answered
F

3

11

I am relatively new to Backbone and I am running into this problem.

I am using Backbone with DustJS

My template looks something like this - index.dust

<div id="parentView">
  <div class="section">
    {>"app/inc/responseMessage" /}
    <div class="userDetails">
      {! A button to get user details !}
    </div>
  </div>
</div>

This is my partial below - responseMessage.dust

<div id="responseMessage">
  {@eq key="{data.success}" value="true"}
    <div class="alert alert-success success" role="alert">success</div>
  {/eq}
</div>

My JS looks like this

initialize: function() {
    this.responseMessageView = this.responseMessageView ||
        new ResponseMessageView({
            model: new Backbone.Model()
        }); // View is for the partial
    this.model = this.model || new Backbone.Model(); //View for the whole page
},

Below function is called when an event occurs and it does a POST and returns successfully.

primaryViewEventTrigger: function(event){
  //Button click on `index.dust` triggers this event and does a POST event to the backend

  this.listenToOnce(this.model, 'sync', this.primaryViewSuccess);//this will render the whole view. 
  this.listenToOnce(this.model, 'error', this.primaryViewError);
  this.model.save({data: {x:'123'}});
}

responseViewEventTrigger: function(event){
  //Button click on `responseMessage.dust` triggers this event and does a POST event to the backend

  this.listenToOnce(this.responseMessageView.model, 'sync', this.responseViewSuccess);//it should only render the partial view - responseMessage.dust
  this.listenToOnce(this.responseMessageView.model, 'error', this.primaryViewError);
  this.responseMessageView.model.save({data: {x:'123'}});
}
primaryViewSuccess: function(model,response){
    this.model.set('data', response.data);
    this.render();
}
responseViewSuccess: function(model,response){
    this.responseMessageView.model.set('data', response.data);
    console.log(this.responseMessageView.model);
    this.responseMessageView.render(); // Does not work in some cases
}

My implementations of the callback function

exports.sendEmail = function sendEmail(req, res){
  req.model.data.success = true;
  responseRender.handleResponse(null, req, res);
};

this.model belongs to the model of the whole page. Whereas this.responseMessageView.model is the model for the partial.

Question: This works perfectly fine in most of the cases. There is one case where it does not render the partial with the latest model values. When I click on the button on index.dust and primaryViewSuccess is executed. After which I click on another button and trigger responseViewEventTrigger. It does the POST successfully and it comes to responseViewSuccess and stores it in the model too. But it does not show it on the frontend. data.success is still not true whereas console.log(this.responseMessageView.model) show that attributes->data->success = true

But the same behavior when I refresh the page it all works perfect. Its just that when primaryViewSuccess is called and then responseViewSuccess its not taking the latest model changes. In other words model is being updated but the DOM remains the same.

What am I missing here? Thanks for your time!

Furtive answered 23/10, 2015 at 20:11 Comment(11)
Are you intentionally passing new model to responseMessageView or are you expecting the model you're referring to in this code to be same..? You seems to be doing this.model.set('data', response.data); this.responseMessageView.model.set('data', response.data); etc and looks like a mess... We don't know what is the thing containing the initialize in first code block... We don't know what is the thing containing the second code block.. you might want to explain the relationships between these views, models etc firstFiftieth
@t-j I have edited the question. I do not understand what do you mean by thing? initialize() is used to declare a view for the whole page and for the partial. Sorry if I am not able to explain myself well.Furtive
By thing I was asking whether it's a view, collection etc... I didn't get what you mean by "Its just that when primaryViewSuccess is called and then responseViewSuccess its not taking the latest model changes." which view is not taking which model changes..? You have 2 views and 2 models. Please explain based on that, who should update based on whom.Fiftieth
One thing I don't understand is the reason for having separate models for both views... they seems to be using the same data this.model.set('data', response.data);... If you use thee same model then it'll be easier to keep both view in sync. Also, you don't have to manually set response.data into model. You can return response.data from parse method, it'll be set automatically.Fiftieth
show me how your POST callback is written pleaseLiles
@FrançoisRichard My Post function looks like this exports.sendEmail = function sendEmail(req, res){ callsomefunction(req, function(err, response){ req.model.data.success = true; responseRender.handleResponse(null, req, res); }); };Furtive
@TJ I use the same model too. It still gives me the same error. responseViewSuccess: function(model,response){ this.model.set('data', response.data); this.responseMessageView.render(); // Does not work in some cases } .. This still does not work :(Furtive
@TJ Answering the first question - There are 2 events occurring. One should trigger the primaryViewSuccess and the other responseViewSuccess. Each of them have their own models and views which needs to be updated. Now if I trigger responseViewSuccess it works perfectly fine. But when I trigger primaryViewSuccess followed by the responseViewSuccess it does not work.Furtive
but how do you use it and update your model that's what I needfLiles
also where is the ajaxcall ? I need to see how you wrote the ajax call not only the callbackLiles
@FrançoisRichard this.model.save() does the POST request.(this is the ajaxcall) this.responseMessageView.model.set('data', response.data); this updates the model and this.responseMessageView.render() should render the view.Furtive
M
5

You're hitting the classic Backbone render-with-subviews gotcha: When you render the index view, you are replacing all of the DOM nodes. That includes the DOM node that your responseMessageView instance is tied to. If you inspect the responseMessageView.el you'll actually see that it has been updated with the new model data, however the element isn't attached to the index's DOM tree anymore.

var Parent = Backbone.View.extend({
  template: _.template(''),
  render: function() {
    this.$el.html(this.template());
  },

  initialize: function() {
    this.render();
    this.child = new Child();
    this.$el.append(child.el);
  }
});

Here when you manually call render, child.el will no longer be in the parent.el (you can check using the inspector).

The simplest fix here is to call child.setElement after the parent renders with the newly rendered div#responseMessage element. The better fix is to detach the responseMessageView's element beforehand, and reattach after:

var Parent = Backbone.View.extend({
  render: function() {
    this.responseMessageView.$el.detach();
    this.$el.html(this.template(this.model.toJSON()));
    this.$el.find('#responseMessage').replaceWith(this.responseMessageView.el);
  }
});
Maud answered 26/10, 2015 at 18:22 Comment(1)
This makes absolutely sense. But since I am using DustJS this does not work for me :/ .. I do this.$el.html(this.template(this.model.toJSON())); The parent view does not show the latest model changes. the html does not show the model changes.Furtive
D
3

Try to use success callback and let me know I think your problem may come from here:

this.model.save( {att1 : "value"}, {success :handler1, error: handler2});

Also are you sure you want to use listenToOnce ? instead of listenTo ??

Darrickdarrill answered 25/10, 2015 at 10:28 Comment(3)
Nope this does not work. My function looks like this this.responseMessageView.model.save({data: {email: emailAddress.val()}}); ..Also I have to mention that the success callback is being fired for sure. As I have console statements in that.Furtive
I tried this this.responseMessageView.model.save({data: {email: emailAddress.val()}}, {success :this.responseViewSuccess, error: this.responseViewError}); .. This does not work :( what am I missing?Furtive
I did listenTo and still no avail :/Furtive
S
3

Try doing this.delegateEvents() after your render (http://backbonejs.org/#View-delegateEvents).

Sip answered 26/10, 2015 at 18:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.