1

So I am fighting with this backbone script. Basically what it should do is: when something in the model changes it needs to render the view again.

All goes well, the change event gets triggered and the view responds. but then when I come back in the render, it lost the model and it lost the element ($el) in the view to which the date needs to be rendered

I created a snippet you can find it here:

var APP = {};

APP.items = [{
   "id": "id_2",
    "alias": "item 2"
  }];
  

APP.newItem2 = {
 "id": "id_2",
  "alias": "item 2",
  "ttile": "here is your title",
  "description": "need I say more?"
}  

APP.ItemModel = Backbone.Model.extend({ 
  initialize: function (attr) {
   console.log(attr);
  },  
  updateStore: function (prod) {
   this.set(prod);
  }  
});

APP.ProductsCollection = Backbone.Collection.extend({
  model: APP.ItemModel,
  initialize: function (mdls) {
    console.log(mdls);  
  }
});

APP.ItemView = Backbone.View.extend({
 initialize: function () {
   this.model.on("change", this.render);
    this.render();
 },  
  render: function () {
   console.log('this: ', this); //this is always known
    console.log('render model: ', this.model); //the second time the model is undefined
    console.log('el: ', this.$el); //the second time the $el is undefined      
      
    var htmlSource = $("#itemContent").html(),
       template = Handlebars.compile(htmlSource),
        compiled = template(this.model);
  
    this.$el.html(compiled);
    
  },
  events: {
   "click .clickBtn": "loadData"
  },
  
  loadData: function (e) {
   this.model.updateStore(APP.newItem2);
  }

});

APP.MainView = Backbone.View.extend({
  el: "#listContainer",
    initialize: function () {
     APP.productsCollection = new APP.ProductsCollection(APP.items);
      this.render();
    },
    
    render: function () {
     var that = this,
          htmlSource = $("#basicContent").html(),
     template = Handlebars.compile(htmlSource),
          compiled = template(APP.productsCollection);
  
     this.$el.html(compiled);
      
      APP.productsCollection.models.forEach(function (model) {
         new APP.ItemView({
          el: "#" + model.attributes.id,
          model: model
         });
      });           
    }        
});
APP.mainView = new APP.MainView();
.maplayer_wrap {
  width: 500px;
  height: 100px;
  background-color: white;
  padding: 10px;
  margin-top: 10px;
  border: 1px solid #CCC;

}
<script src="https://code.jquery.com/jquery-3.2.1.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.3.3/backbone.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.10/handlebars.js"></script>

<div id="listContainer">
  
</div>

<script id="basicContent" type="text/x-handlebars-template">
    {{#each models}}
    <div class="maplayer_wrap" id="{{id}}">Loading... </div>
    {{/each}}
</script>

<script id="itemContent" type="text/x-handlebars-template">

    <span class="maplayer_image">
        new data...
    </span>

    <div class="maplayer_content">

        <p class="maplayer_content_head">{{attributes.title}}</p>
        <p class="maplayer_content_txt">{{attributes.description}}</p>

    </div>

    <span class="maplayer_icon">
        <i class="fa fa-map-o fa-fw" aria-hidden="false"></i>
    </span>
    
    <button class="clickBtn">
     click!
    </button>

</script>

If you like jsfiddle you can find a copy here: https://jsfiddle.net/rwqwfz8b/50/

How do I solve this problem?

Edit: In the meanwhile I am looking for a solution myself. What I found is the first time I render the view all is well. However, when the model changes and the view renders again it seems like the view thinks it is the model in stead of the view.

Therefor it loses all data and cannot be rendered again.

BonifatiusK
  • 2,281
  • 5
  • 29
  • 43

1 Answers1

0

Found it!

In the view where I set the listener I now also added 'this' and now it works

Problem:


this.model.on("change", this.render);

Solution:


this.model.on("change", this.render, this);

BonifatiusK
  • 2,281
  • 5
  • 29
  • 43
  • 4
    You should [use `this.listenTo(this.model, 'change', this.render);` instead to avoid memory leaks](https://stackoverflow.com/q/16823746/1218980). – Emile Bergeron Oct 11 '17 at 14:12