2016-10-31 26 views
0

我已经使用下划线模板配置了一个简单的骨干模型和视图。完全相同的配置用于两个独立的API。渲染没有被调用一个API并且是另一个

API 1按预期工作。

要重现该问题,注释掉的URL API 1,取消对URL的API 2.

正如你可以看到我已经规范了两种API响应数据,完全相同的数据结构为两个apis返回。但是,不调用API 2的渲染方法。更奇怪的是,在极少数情况下渲染确实被API 2调用。

我在这里丢失了什么?

// 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() { 
 
\t var quoteV = new QuoteView({ 
 
\t \t el: $('#quote'), 
 
\t \t model: quoteM 
 
\t }); 
 
});
<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"> 
 
\t \t <p>The author is : <%= author %></p> 
 
\t \t <p>The content is : <%= quote %></p> 
 
</script> 
 

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

回答

1

你有竞争条件,在那里你创建视图之前提取。

因此,如果抓取在文档准备好之前完成,则在视图开始侦听模型之前触发change事件。

最简单的办法

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

最好的解决办法

var API_DOMAIN = "http://quotes.rest/"; 
 
// Reusable model 
 
var Quote = Backbone.Model.extend({}); 
 

 
// reusable quotes collection 
 
var QuoteCollection = Backbone.Collection.extend({ 
 
    model: Quote, 
 
    // simple generic parse 
 
    parse: function(response) { 
 
    return response.contents.quotes; 
 
    }, 
 
}); 
 

 
// View 
 
var QuoteView = Backbone.View.extend({ 
 
    // GOOD: gets called once 
 
    template: _.template($('#quote-template').html()), 
 
    
 
    initialize: function() { 
 
    // BAD: gets called for every view 
 
    // 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.toJSON())); 
 
    // Backbone standard for chaining 
 
    return this; 
 
    } 
 
}); 
 

 

 
$(function() { 
 
    var quoteV, 
 
    collection = new QuoteCollection(); 
 
    collection.fetch({ 
 
    url: API_DOMAIN + 'qod.json', 
 
    success: function(collection, response, options) { 
 
     // only create the view when you need it 
 
     quoteV = new QuoteView({ 
 
     el: $('#quote'), 
 
     model: collection.first() 
 
     }); 
 
     
 
     // manually render to be 100% in control. The event now only 
 
     // serves if the model really changes. 
 
     quoteV.render(); 
 
    } 
 
    }); 
 

 
});
<div id="quote"></div> 
 

 
<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>

+0

谢谢!不能相信我错过了这一点。 – arctelix

+0

@arctelix我已经将Backbone的最佳实践添加到了我的答案中。 –

+0

感谢您的更新答案! – arctelix

1

添加一些日志记录在你的报价模型的事件,你应该能够迅速追查问题。

var Quote = Backbone.Model.extend({ 
    initialize: function() { 
     this.on('all', function(eventName) { 
      console.debug('QuoteModel: ' + eventName); 
     }); 
    } 
}); 
+0

我已经添加了额外的日志记录,唯一不同的是,使被调用API 1,而不是API 2 ... – arctelix

相关问题