2016-10-31 3 views
0

J'ai configuré un simple modèle de base et une vue à l'aide d'un modèle de soulignement. La même configuration est utilisée pour deux API distinctes.Rendu sans appel pour une API et pour une autre

API 1 fonctionne comme prévu.

Pour reproduire le problème, commentez l'url pour API 1 et décommenter l'URL pour l'API 2.

Comme vous pouvez le voir, j'ai normalisé les données de réponse pour les deux apis, la structure même de données exactes est retourné pour les deux apis. Toutefois, la méthode de rendu pour API 2 n'est pas appelée. Pour rendre les choses encore plus étranges, en de rares occasions, le rendu est appelé par l'API 2.

Qu'est-ce qui me manque ici?

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

Répondre

1

Vous avez une condition de course , où vous allez chercher avant de créer la vue. Par conséquent, si l'extraction se termine avant que le document ne soit prêt, l'événement change est déclenché avant que la vue ait commencé à écouter le modèle.

La solution

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

La meilleure solution

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

Merci! Je ne peux pas croire que j'ai raté ça. – arctelix

+0

@arctelix J'ai ajouté les meilleures pratiques de Backbone à votre code dans ma réponse. –

+0

Merci pour la nouvelle mise à jour! – arctelix

1

Ajouter une consignation pour les événements sur votre modèle de devis, et vous devriez être en mesure de suivre rapidement le problème.

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

plus simple que j'ai ajouté l'enregistrement supplémentaire, la seule différence est que render est appelé à l'API 1 et non API 2 ... – arctelix