arctelix arctelix - 1 month ago 11
Javascript Question

render not getting called for one api and is for another

I have configured a simple backbone Model and View using an underscore template. The exact same configuration is used for two separate APIs.

API 1 works as expected.

To reproduce the problem, comment out the url for API 1 and uncomment the url for API 2.

As you can see I have normalized the response data for both apis, the exact same data structure is returned for both apis. However, the render method for API 2 is not called. To make matters even more strange, on rare occasions render does get called by API 2.

What am I missing here?



// Model
var Quote = Backbone.Model.extend({
// API 1
//urlRoot: 'http://quotes.stormconsultancy.co.uk/quotes/1.json',

// API 2
urlRoot: 'http://quotes.rest/qod.json',

parse: function (data){
try{
data = data['contents'].quotes[0];
}
catch(e){
}

var rd = {author:data.author, quote:data.quote}
console.log("parsed", typeof rd, rd);
return rd;
},

// UPDATE as suggested by cory
initialize: function() {
this.on('all', function(eventName) {
console.log('QuoteModel: ' + eventName);
});
}
});

// View
var QuoteView = Backbone.View.extend({
initialize: function() {
this.template = _.template($('#quote-template').html());
this.listenTo(this.model, 'change', this.render);
},

render: function(){
console.log("render", this.model.attributes)
this.$el.html(this.template(this.model.attributes));
}
});

var quoteM = new Quote();
quoteM.fetch();

$(document).ready(function() {
var quoteV = new QuoteView({
el: $('#quote'),
model: quoteM
});
});

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.3.3/backbone-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.5/handlebars.min.js"></script>

<script type="text/html" id="quote-template">
<p>The author is : <%= author %></p>
<p>The content is : <%= quote %></p>
</script>

<div id="quote"></div>




Answer

You have a race condition, where you fetch before creating the view.

So if the fetch finishes before the document is ready, the change event gets triggered before the view has started listening to the model.

The simplest solution:

$(document).ready(function() {
    var quoteM = new Quote();
    var quoteV = new QuoteView({
        el: $('#quote'),
        model: quoteM
    });
    // fetch after
    quoteM.fetch();
});
Comments