如何在示例Backbone.js待办事项列表应用程序中构建两个嵌套列表?

时间:2012-08-22 09:59:05

标签: backbone.js

我正在开发Backbone中的示例ToDo列表项目,我想了解框架如何更喜欢在嵌套列表场景中组织其视图和模型。

为了澄清我的意思,我的单页Backbone应用程序应该显示ToDo列表的列表。从后端的角度来看,有一个List资源和一个Item(todo列表中的单个条目)资源。有点像:

  • 星期一家务
    • 拿起邮件
    • 洗衣服
    • 拿起干洗
  • 杂货清单
    • 芹菜
    • 牛肉
    • 你明白了......

由于我是一个Rails 3.2应用程序,我隐约地遵循Railscasts Backbone.js教程,所以这就是我从中获取当前设计的地方。我很想知道我是否完全脱离了Backbone规定的模式,或者我是否在正确的轨道上!

我到目前为止:

ListsIndex View                         //index of all lists
\-- ListsCollection
     \-- ListView / Model               //individual list
          \-- ItemsIndex View           //index of items in one list
              \-- ItemsCollection
                  \-- Item View / Model //individual todo item

流程将是:

  1. 在路由器初始化时,fetch()收集/列出后端路由上的列表。在ListsIndex的集合部分的'reset'事件中,对集合中的每个项执行render(),并附加到列表索引视图模板。
  2. 在每个项目视图的初始化方法中(是你在哪里连接第二级获取?)fetch()来自/ lists /:id / items后端路由的项目到特定于该视图的ItemsCollection。
  3. 在同一方法中,实例化ItemsIndex对象并将集合传递给它。再次,在ItemsIndex中,有一个'reset'事件处理程序,用于填充集合时,此时它应该从项集合中呈现每个获取的模型并将它们附加到自己的视图中。
  4. 我基本上采用了List的设计,并将其镜像到一个级别。不同之处在于我不再需要依赖路由器。因此,我使用ListView的initialize方法产生类似的效果。

    是的/不?超级错了?谢谢!

1 个答案:

答案 0 :(得分:3)

TL:DR; 1)我会引导你的初始数据而不是fetch()reset()。 2)您可以根据需要在View的初始化中进行提取。或者您可以在开始时加载数据。请记住,如果您在init中获取,则异步性质将不会在渲染时准备好数据。如果你有一个等待同步/添加/等的监听器,这不是问题。 3)我不知道你对itemIndex对象的意思,但是你可以根据需要创建对象并添加它们。或者你可以在开始时加入,如果你知道你的所有列表最终将有一个集合。您可以根据需要重置(除非您给它选项{add:true},否则自动执行此操作)或者只是在它们进入时逐个添加它们虽然reset(),删除先前的视图,渲染所有视图似乎是人们通过完全获取()来做事的常用方法。

我认为它看起来很不错。关于Backbone的好处是你可以用很多不同的方式做到这一点。例如,您的数字2表示从视图中连接第二个fetch()。如果你想延迟加载,你可以这样做。或者你可以在任何事情完成之前抓住应用程序启动时的所有数据。这完全取决于你。我就是这样做的。

这就是我如何制作这样的应用程序(只是我的偏好,我不知道它更好或更差,或者它与你描述的相同。)

首先,我将创建一个名为ListModel的模型。它会有一个id和一个名字attr。这样,您就可以创建许多单独的列表,每个列表都有自己可以单独获取的ID。

每个ListModel都有一个ItemsCollection。这个集合有一个基于ListModel的URL,它是它的一部分。因此,ListModel-1的集合URL类似于/ list / 1

最后你有ItemModel,它是一个资源ID和文本。

ListCollection
    ListModel  // Monday Chores
        ItemCollection
            ItemModel  // Mail
            ItemModel  // Laundry
            ItemModel  // Drycleaning
    ListModel  // Grocery
        ItemCollection
            ItemModel  // Celery
            ItemModel  // Beef

所以在这个小小的展示中,你会注意到我还没有把任何与视图有关的东西。我不知道它是否更像是一个概念性的东西,但这就是数据层次结构的样子,你的观点可以完全独立于它。我不确定你是如何将上述观点纳入其中的,但我认为这可能会让它更清晰。

至于定义这些结构,我认为有两件事。

首先,我要确保我的ListModel已在我的集合中定义。这样我就可以使用集合add(hash)在我生成/添加它们时实例化新模型。

其次,我将定义ListModel,以便在创建一个ListModel时,它会自动创建一个ItemCollection作为该ListModel对象的属性(而不是属性)。

理想情况下,您的ListModel将是这样的:

ListModel.ItemCollection

在应用初始化之前,我会引导数据而不是fetch()。 (这种地址指出你所做的一点)理想情况下,当你的Backbone应用程序启动时,它应该具有从get go开始所需的所有必要数据。我会传递一些像这样的数据:

 var lists = [listModel-1-hash, listModel-2-hash];

现在,当应用程序启动时,您可以立即创建这两个列表。

var myLists = new ListCollection();

_.each(lists, function(hash) {
    myLists.add(hash);  // Assumes you have defined your model in the ListCollection
}

现在,您的列表集合包含所需的所有列表模型。

以下是视图的来源。您可以将任何内容传递给任何视图。但我可能会将观点分为三个方面。

AppView,ListModelView,ItemModelView就是这样。

想象一下这样的结构:

<body> // AppView
    <ul class="List"> // ListModelView
        <li class="Item"></li>     // ItemModelView
    </ul>
    <ul class="List"> // ListModelView
    </ul>
</body>

当您启动应用程序并创建AppView时,在AppView中,您将生成每个ListModelView并将其附加到正文。我们的清单是空的。也许当你点击它懒惰加载项目。这就是你如何把它搞定的。

// In ListModelView
events: {'click':'fetchItems'}

fetchItems: function() {
    this.model.itemCollection.fetch();  // Assumes you passed in the ListModel into view
}

因此,自从我开始引导数据以来,这个fetch()调用将是你的“第二次”获取。 (我正在解决你所做的第2点。)你可以在初始化中获取它。请记住它是一个异步函数,所以如果你在渲染时需要它们,它将无法工作。但是,您可以做的是向此视图添加事件侦听器,以侦听向itemCollections添加事件。

this.model.itemCollection.on('add', this.addItemView, this);

addItemView()将生成itemViews的新实例并附加它们。

对于第3点,您可以在需要时实例化一个集合并将其放入ListModel中。或者你可以做我做的事情,并确保你的模型总是有一个ItemCollection。这取决于您的偏好和目标。你可能不需要这一切,但我觉得由于某种原因说明了。我不知道,也许有帮助。