【问题标题】:How to wait to render view in backbone.js until fetch is complete?如何等待在backbone.js中渲染视图直到获取完成?
【发布时间】:2012-02-12 16:40:29
【问题描述】:

我正在尝试了解backbone.js 的一部分是如何工作的。应用程序启动后,我必须获取模型集合。我需要等到 fetch 完成才能呈现每个视图。 我不能 100% 确定在这种情况下采取的最佳方法。

var AppRouter = Backbone.Router.extend({
    routes: {
        "": "home",
        "customer/:id": "customer" 
    },

    home: function () {
        console.log("Home");
    },

    customer: function (id) {
        if (this.custromers == null)
            this.init();

        var customer = this.customers.at(2); //This is undefined until fetch is complete. Log always says undefined.
        console.log(customer);
    },

    init: function () {
        console.log("init");
        this.customers = new CustomerCollection();
        this.customers.fetch({
            success: function () {
                console.log("success"); 
                // I need to be able to render view on success.
            }
        });
        console.log(this.customers);
    }
});    

【问题讨论】:

  • 你知道你提前得到了多少对象吗?为什么要等到它们全部关闭后再渲染。你能不能把页面设计成允许每个对象呈现自己并将其附加到 Dom 上?
  • 当我尝试运行 this.customers.at(2) 并抓取第二个对象时,它总是返回未定义,除非我等到获取成功触发。我假设,这是我做错了并且没有完全理解的事情。我对 JScript 很陌生。
  • 仅供参考。它是 JavaScript 而不是 jscript。 Jscript 是微软的混蛋子变种。但是是的,fetch 是非阻塞的,这意味着如果你调用 fetch,无论 fetch 的结果如何,下一个命令都会运行。看看我下面的答案。

标签: javascript asynchronous backbone.js


【解决方案1】:

我使用的方法是这样的jQuery完成回调:

var self = this;
this.model.fetch().done(function(){
  self.render();
});

这是在 Backbone bug report 中推荐的。尽管错误报告建议使用complete,但该回调方法已被deprecated 支持done

【讨论】:

  • 这非常简单,而且效果很好。我强烈推荐这个答案。
  • Michael,你肯定也在其他地方调用了渲染函数。也许在你实例化你的视图之后?
  • 我认为在其内部渲染视图是不明智的。这很容易出错。
  • @BonifatiusK 为什么?你建议在哪里放置渲染函数?
  • @BonifatiusK 您没有回答为什么上述答案中提出的方法比从其他地方触发渲染函数更容易出错。当然每个开发者都应该使用自己的判断,但是这个sn-p将所有与视图相关的代码保留在视图中。在另一个文件中包含与视图相关的代码只会使代码难以解开。但是在某些情况下,您肯定不想在获取完成后直接渲染视图,但这样做正是问题所要求的 - 一种延迟渲染直到获取完成的方法。
【解决方案2】:

你也可以用 jquery 1.5+ 做到这一点

$.when(something1.fetch(), something2.fetch()...all your fetches).then(function() {
   initialize your views here
});

【讨论】:

  • 不知道这存在。谢谢。
  • 我正在尝试获取集合,但它不起作用。它给了我 json 而不是 the_value 的集合:$.when(collection.fetch()).then(function(the_value){console.log(the_value)})
  • 这是并联逻辑还是串联逻辑?
【解决方案3】:

您可以将自己的 options.success 发送到仅在提取完成时运行的集合 fetch 方法


编辑(超级迟到!)

来自主干源(从 0.9.1 中的第 624 行开始)

fetch: function(options) {
  options = options ? _.clone(options) : {};
  if (options.parse === undefined) options.parse = true;
  var collection = this;
  var success = options.success;
  options.success = function(resp, status, xhr) {
    collection[options.add ? 'add' : 'reset'](collection.parse(resp, xhr), options);
    if (success) success(collection, resp);
  };

注意倒数第二行。如果您已将 options 对象中的函数作为 success 键传入,它将在集合被解析为模型并添加到集合后调用它。

所以,如果你这样做:

this.collection.fetch({success: this.do_something});

(假设initialize 方法将this.do_something 绑定到this...),它将在整个shebang 之后调用该方法,允许您在获取/解析/附加之后立即触发操作

【讨论】:

  • 我正在打电话等着修车:)。我回家后会做的!仅供参考,主干源代码有很好的注释和注释。与此同时,您可能只想看看 fetch
  • 太棒了。非常感谢您的帮助!
  • @tkone 还在用手机吗? :)
  • @ScottGreenfield 哇,那个让我忘记了。这就是我所说的。
  • 我不希望我的模型或集合在我的主干定义 JS 文件中对视图有任何引用。这种方法可以让我避免这种情况。谢谢
【解决方案4】:

另一种有用的方法可能是在页面加载时直接引导数据。这个如果来自
FAQ:

加载自举模型

当您的应用首次加载时,通常会有一组您知道您将需要的初始模型来呈现页面。与其触发额外的 AJAX 请求来获取它们,更好的模式是让它们的数据已经引导到页面中。然后,您可以使用 reset 使用初始数据填充您的集合。在 DocumentCloud,在工作区的 ERB 模板中,我们按照以下方式进行操作:

<script>
  var Accounts = new Backbone.Collection;
  Accounts.reset(<%= @accounts.to_json %>);
  var Projects = new Backbone.Collection;
  Projects.reset(<%= @projects.to_json(:collaborators => true) %>);
</script>

【讨论】:

    【解决方案5】:

    另一种选择是在您的集合初始化方法中添加以下内容:

    this.listenTo(this.collection, 'change add remove update', this.render);
    

    每当提取完成和/或以编程方式更新集合时,这将触发渲染方法。

    【讨论】:

      【解决方案6】:

      您可以使用 on 和 Off 方法

      如果你想添加触发方法,比如假设你想成功,你想调用渲染方法,所以请按照下面的例子。

          _this.companyList.on("reset", _this.render, _this);
          _this.companyList.fetchCompanyList({firstIndex: 1, maxResult: 10},     _this.options);
      

      在Model js中请使用like

          fetchCompanyList: function(data, options) {
          UIUtils.showWait();
          var collection = this;
          var condition = "firstIndex=" + data.firstIndex + "&maxResult=" + data.maxResult;
          if (notBlank(options)) {
              if (notBlank(options.status)) {
                  condition += "&status=" + options.status;
              }
          }
          $.ajax({
              url: "webservices/company/list?" + condition,
              type: 'GET',
              dataType: 'json',
              success: function(objModel, response) {
                  UIUtils.hideWait();
                  collection.reset(objModel);
                  if (notBlank(options) && notBlank(options.triggerEvent)) {
                      _this.trigger(options.triggerEvent, _this);
                  } 
              }
          });
      }
      

      【讨论】:

        猜你喜欢
        • 2016-01-24
        • 1970-01-01
        • 1970-01-01
        • 2020-12-09
        • 2013-05-14
        • 2018-05-02
        • 1970-01-01
        • 2018-08-03
        • 1970-01-01
        相关资源
        最近更新 更多