javascript - 主干集合获取渲染在第一次加载时使用路由器运行两次

标签 javascript backbone.js

我对 Backbone 相当陌生,正在尝试了解路由器并从数据库调用集合。

我有以下内容 收藏:

var Scorecards = Backbone.Collection.extend({
 model:Scorecard,
 url:"http://localhost:3002/api/scorecards",

initialize:function(){
  this.fetch({
    success: this.fetchSuccess,
    error: this.fetchError
  });
},

fetchSuccess: function (collection, response) {
  console.log("results");
  if(collection.length>0) {
    var view = new ScorecardsView({el:'#scorecards-container', model:scorecards});
    view.render();
  }
  else{
    var view = new NoScorecardsView({el:'#scorecards-container'});
    view.render();
  }

},

fetchError: function(collection, response) {
  throw new Error("Failed to get scorecards");
}
});

路由器:

var ScorecardRouter = Backbone.Router.extend ({ 
routes: { 
  '' : 'home', 
  'create': 'createScorecard',
  'edit': 'editScorecard'
},

home: function () { 
  console.log("Home view");
  var view = new ScorecardsView({el:'#scorecards-container', model:scorecards});
  view.render();     
}, 
createScorecard: function () { 
  console.log('Create view');
  var view = new CreateScorecardView({el:'#scorecards-container'});
  view.render();
}
});

记分卡 View :

var ScorecardsView = Backbone.View.extend({
initialize: function(){
  this.model.on('destroy', this.render, this);
},

render: function() {
  console.log("Scorecard render");
  var self = this;

  this.$el.html(ScorecardContTemp);
  this.model.each(function(scorecard){
    var scorecardView = new ScorecardView({model:scorecard});
    self.$('.scorecards-items tbody').append(scorecardView.render().$el);
  });
},

events: {
  "click #scorecard-create-btn" : "createScorecardView",
},

createScorecardView: function(e) {
  e.preventDefault();
  scorecardRouter.navigate('create', {trigger: true});
}
});

我就以此开始

  var scorecards = new Scorecards; 
  var scorecardRouter = new ScorecardRouter(); 
  Backbone.history.start(); 

我的问题是,当我第一次到达主路线时, View 渲染函数运行了两次。因为首先 fetch 正在调用它,并且路由也正在调用它。

我需要从获取成功或路由中删除调用,但是当我这样做时,我在初始加载时没有得到任何结果,我必须导航到不同的路由并返回。

你应该如何实现这一目标?因此,我可以获取一次结果,然后通过获取成功的路线显示它们,而且当用户导航到它时也可以在 route 显示它们。

我希望这是有道理的?

任何帮助都会很棒。

最佳答案

首先,您的数据不应该知道它是如何呈现的,因此模型或集合中任何位置的 new View() 都是问题的明确标志。您的 View 应该观察数据并自行更新。

您的另一个可能的困惑来源是将 {trigger: true} 传递给您的路由器 navigate 方法。带来什么样的麻烦,在这篇经典的Backbone文章中详细解释了:Don’t Execute A Backbone.js Route Handler From Your Code .

现在,您绝对应该从集合中删除 View 渲染。相反,您的 View 应该了解集合并在数据更改时自行更新。

以下是我如何设置 View 来观看集合的示例:

/** Scorecard model */
var Scorecard = Backbone.Model.extend({
  defaults: {
    name: '',
    email: ''
  }
});

/** Scorecard View (I know it totally doesn't look like a scorecard, just an example view)  */
var ScorecardView = Backbone.View.extend({
  template: _.template('<%=name%>, <em><%=email%></em>'),
  render: function(){
    this.$el.html( this.template( this.model.toJSON() ) );
    return this;
  }
});

/** Collection */
var Scorecards = Backbone.Collection.extend({
  model: Scorecard,
  
  /** using fake api for the sake of this example to work */
  url: "http://jsonplaceholder.typicode.com/users",

  initialize:function(){
    this.fetch({
      success: this.fetchSuccess,
      error: this.fetchError
    });
  },

  fetchSuccess: function (collection, response) {
    console.log("results:", collection);
  },

  fetchError: function(collection, response) {
    throw new Error("Failed to get scorecards");
  }
});


/** Scorecards view: */

var ScorecardsView = Backbone.View.extend({
  initialize: function(){
    this.collection.on('destroy', this.render, this);
    
    /** render one added item whenever it comes to collection */
    this.collection.on('add', this.addOne, this);
  },

  render: function() {
    console.log("Scorecard render");
    
    /** clean the items container, 
        which will be useful when items get destroyed
        and we'll want to re-render whole collection */
    this.$el.find('.scorecards-items').empty();
    
    /** in case collection already has data, let's render it */
    this.collection.each(this.addOne, this);
  },
  addOne: function(scorecard){
    var scorecardView = new ScorecardView({ model: scorecard });
    this.$('.scorecards-items').append(scorecardView.render().$el);
  }
});


/** Router: */

var ScorecardRouter = Backbone.Router.extend ({ 
  routes: { 
    '' : 'home'
  },
  home: function () { 
    console.log("Home view");
    var view = new ScorecardsView({
      el:'#scorecards-container',
      collection: scorecards
    });
    view.render();     
  }
});


/** starting things off */

var scorecards = new Scorecards(); 
var scorecardRouter = new ScorecardRouter(); 
Backbone.history.start();
<script src='http://code.jquery.com/jquery.js'></script>
<script src='http://underscorejs.org/underscore.js'></script>
<script src='http://backbonejs.org/backbone.js'></script>

  <div id="scorecards-container">
    <div class="scorecards-items"></div>
  </div>

关于javascript - 主干集合获取渲染在第一次加载时使用路由器运行两次,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33221817/

相关文章:

javascript - 如何根据数组值对html元素进行排序

javascript - 如何使用 Javascript 获取多个输入字段的值

javascript - 淡入文档片段

javascript - 播放期间跳过部分YouTube视频

javascript - 通过 javascript 设置 IE 特定的 css 样式

javascript - 在 backbone.js 中触发任一事件但不会同时触发

javascript - Ampersand.js(或 Backbone.js)中的模型可以同时存在于多个集合中吗?

javascript - Backbone 集合验证

javascript - 在客户端编译时,Handlebars Uncaught [object Object] 错误

javascript - facebook graph api ajax XMLHttpRequest - 空结果?