构建几个深层嵌套数据的视图

时间:2014-09-01 09:15:35

标签: marionette

我正在尝试使用服务器端的django / tastypie和客户端的backbone / marionette为朋友构建订单系统。服务器端没有什么大问题,但由于我是一个没有经验的前端开发人员,我有点卡住了;

更简单的情况很好,例如使用Composite-和ItemViews列出,添加,编辑和删除文章(只是我的数据库中的一个表,包括sku,描述等)。问题是我正在尝试构建一个Order的视图,因为它包含几个表在服务器端有关系。

订单
LineItem的
文章
StoreQuantity
商店
StoreQuantity
商店

的LineItem
文章
StoreQuantity
商店
StoreQuantity
商店

  ...

因此订单包含多个LineItem。 LineItem由一个文章和几个StoreQuantity组成:s可以模拟诸如“订购商品A;商品X的10份和商店Y的4份副本,商品X;商店X的4份副本和商店Y的1份”

我想我的问题是;我将如何为上述内容构建我的观点?

下面的内容会是错误的吗?

  • 创建一个OrderCompositeView并从我的控制器传递OrderModel。

  • 从服务器获取OrderModel时,让OrderCompositeView创建一个LineItemCompositeView。

  • 当LineItemCompositeView从服务器获取其'LineItemCollection时......依次递归

我是否应该创建一个REST-url,它返回Order的整个JSON及其关系,而不是几个较小的递归调用,然后尝试解析JSON客户端?

我找到了几个关于如何使用Marionette的好资源但没有关于如何处理嵌套多层深层数据的资源。

谢谢/马格努斯

编辑:

显示一些代码,说明我一直在测试的内容

(查看)

var LineItemDetailView = Backbone.Marionette.ItemView.extend({
    template: "#lineitem-layout-template",
    tagName: "div",

    initialize: function() {
    }
});

var LineItemView = Backbone.Marionette.CompositeView.extend({
    template: "#lineitem-wrapper-template",
    childView: LineItemDetailView,
    childViewContainer: "div",

    initialize: function(coll, obj) {
        this.collection = new LineItemCollection({url: "api/v1/lineitem/?order__id=" + obj["order_id"]});
        this.collection.fetch({
            success: function() {
                console.log("Successfully fetched lineitems");
            }

        });
    }
});

var OrderDetailView = Backbone.Marionette.CompositeView.extend({
    template: "#order-detail-template",
    childView: LineItemView,
    childViewContainer: "#lineitems",

    initialize: function() {
        this.model.on("sync", function(mod) {
           lineitemView = new LineItemView([],{order_id: mod.get("id")});
        });
    }
});

这些方面的东西。 OrderDetailView是从我的控制器创建的并传递了OrderModel。我从这里得到OrderDetailView:s模板来渲染,LineItemCollection从服务器获取,但没有更多的事情发生。

1 个答案:

答案 0 :(得分:0)

所以我在前几天创建应用程序的调查部分时遇到了这个问题。它有这样的结构: 调查:    题:       回答       回答    题:       回答       答案

非常类似于你正在做的事情。我使用骨干关系宝石 - http://backbonerelational.org/将模型联系在一起并且效果很好。我的API在一次调用中发送回所有JSON。所以survey / 1.json会带回所有上述部分/他们的数据。然后我用Backbone关系解析/分解它们。这是他们的样子:

调查:

class Entities.Survey extends App.Entities.Model
    urlRoot: "surveys"

    defaults: 
      status: "Draft"
      number_taken: 0
      survey_limit: 500

    relations: [
      type: Backbone.HasMany
      key: "questions"
      relatedModel: Entities.Question
      reverseRelation: 
        key: 'survey'
        includeInJSON: 'id'
    ]

问题:

class Entities.Question extends App.Entities.Model
    urlRoot: "questions"

    defaults:
      single_response: true
      terminate: false
      free_text: false

    relations: [
      type: Backbone.HasMany
      key: "answers"
      relatedModel: Entities.Answer
      reverseRelation: 
        key: 'question'
        includeInJSON: 'id'
    ]

答案:

class Entities.Answer extends App.Entities.Model
    urlRoot: "answers"

    defaults:
      branching: false
      next_question_id: null

然后当你去显示它们时,在我的调查显示视图中,我有一个布局视图,其中有一个问题区域,它使用调查问题的复合视图,如下所示:

class Show.Controller extends App.Controllers.Application

    initialize: (options) ->
      { survey, id } = options
      survey or= App.request "survey:entity", id

      App.execute "when:fetched", survey, =>
        @layout = @getLayoutView()

        @listenTo @layout, "show", =>
          @panelRegion survey
          @questionRegion survey
          @bannerRegion survey

        @show @layout

    questionRegion: (survey) ->
      App.request "show:survey:questions", survey, @layout.questionRegion

然后我进来得到问题:

questionRegion: (survey) ->
      questions = survey.get('questions')
      questionView = @getQuestionView questions, survey

问题的子视图CompositeView本身就是一个带有子视图答案的CompositeView。

所以Survey有一个问题CompositeView of Questions,每个都是一个复合视图的答案。

您应该可以在应用中遵循类似的结构。如果你被困在任何地方,请告诉我!

编辑:添加视图/控制器。

所以这就是我做的,当用户导航到某个路线时 - 比如localhost:3000 /#surveys / 1 /编辑它命中我的surveyrouter(注意一些代码,比如我删除的列表部分):

@TheoremReach.module "SurveysApp", (SurveysApp, App, Backbone, Marionette, $, _) ->

  class SurveysApp.Router extends Marionette.AppRouter
    appRoutes:
      "surveys"             : "list"
      "surveys/:id"         : "show"
      "surveys/:id/take": "take"

  API =
    show: (id, survey) ->
        new SurveysApp.Show.Controller
            id: id
            survey: survey

    take: (id, survey) ->
      new SurveysApp.Take.Controller 
        id: id 
        survey: survey

  App.vent.on "survey:clicked", (survey) ->
    App.navigate "surveys/" + survey.id
    API.show survey.id, survey

  App.vent.on "take:survey:button:clicked", (survey) ->
    App.navigate "surveys/" + survey.id + "/take"
    API.take survey.id, survey

  App.addInitializer ->
    new SurveysApp.Router
      controller: API

所以我可以在导航或触发“调查:点击”事件时到达此处。然后创建我的节目控制器:

@TheoremReach.module "SurveysApp.Show", (Show, App, Backbone, Marionette, $, _) ->

  class Show.Controller extends App.Controllers.Application

    initialize: (options) ->
      { survey, id } = options
      survey or= App.request "survey:entity", id

      App.execute "when:fetched", survey, =>
        @layout = @getLayoutView()

        @listenTo @layout, "show", =>
          @panelRegion survey
          @questionRegion survey
          @bannerRegion survey

        @show @layout

    questionRegion: (survey) ->
      App.request "show:survey:questions", survey, @layout.questionRegion

    panelRegion: (survey) ->
      panelView = @getPanelView survey

      @listenTo panelView, "new:question:clicked", (args) ->
        question = App.request "new:question:entity"
        model = args.model
        model.get('questions').add(question)
        question.set(survey_id: model.get('id'))
        App.request "new:question:added"

      @show panelView, region: @layout.panelRegion

    bannerRegion: (survey) ->
      bannerView = @getBannerView survey

      @listenTo bannerView, "take:survey:button:clicked", (args) ->
        App.vent.trigger "take:survey:button:clicked", args.model

      @show bannerView, region: @layout.bannerRegion

    getLayoutView: ->
      new Show.Layout

    getBannerView: (survey) ->
      new Show.Banner
        model: survey

    getPanelView: (survey) ->
      new Show.Panel
        model: survey

这使得一个新的问题显示控制器(与上面相同的路由器案例处理"show:survey:questions"请求并启动一个新的控制器,所以我将跳过该代码。)

@TheoremReach.module "QuestionsApp.Show", (Show, App, Backbone, Marionette, $, _) ->

  class Show.Controller extends App.Controllers.Application

    initialize: (options) ->
      { survey } = options
      @layout = @getLayoutView()

      @listenTo @layout, "show", =>
        @questionRegion survey

      @show @layout

    questionRegion: (survey) ->
      questions = survey.get('questions')
      questionView = @getQuestionView questions, survey

      App.reqres.setHandler "new:question:added", ->
        questionView.render()

      @show questionView, region: @layout.questionRegion

    getLayoutView: ->
      new Show.Layout

    getQuestionView: (questions, survey) ->
      new Show.Questions
        collection: questions
        model: survey

问题的标准复合视图:

class Show.Questions extends App.Views.CompositeView
    template: "questions/show/_questions"
    className: "questions"
    itemViewContainer: ".editor"
    itemView: Show.Question 

然后每个问题都是一个复合视图:

class Show.Question extends App.Views.CompositeView
    template: "questions/show/_question"
    id: "1000"
    className: "step"
    initialize: ->
      @collection = @model.get("answers")
      @model.set(question_number: @model.collection.indexOf(@model) + 1)
      if @model.get('free_text') and @model.get('answers').length < 1
        answer = App.request "new:answer:entity"
        answer.set(free_text: true, question: @model, title: @model.get('title'))
        @collection.reset(answer, {silent: true})
      @on "childview:answer:delete:clicked", (child, args) =>
        args.collection = @model.get('answers')
        @trigger "answer:delete:clicked", args

    itemView: Show.Answer 
    itemViewContainer: ".answer-container"

它从骨干关系中的答案组中获取其集合。我会注意到,这可能只是一个布局,在初始化函数中,我应该向答案应用程序发送请求以获取答案列表并将其添加到答案区域。我还没有解决这个问题:)。