Backbone.js和嵌入式一对多关联

时间:2012-02-11 21:52:53

标签: javascript json mongodb backbone.js coffeescript

应用布局

我正在构建一个可以创建调查的应用程序。每项调查都有多个问题。我将问题嵌入到调查模型中(在Mongoid中使用embeds_many),因此调查可能如下所示:

{
  "id":    "4f300a68115eed1ddf000004",
  "title": "Example Survey",
  "questions": 
  [
    {
      "id":      "4f300a68115eed1ddf00000a",
      "title":   "Please describe your experience with backbone.js", 
      "type":    "textarea"
    },
    {
      "title":   "Do you like it?", 
      "id":      "4f300a68115eed1ddf00000b",
      "type":    "radiobutton",
      "options": ["Yes", "Yes, a lot!"]
    }
  ]
}

现在,还有一个调查编辑器,其中包含SurveyView,显示调查并列出问题。如果我点击一个问题,会弹出QuestionView,我可以在其中编辑问题。当我对我的调查感到满意并点击保存时,SurveyModel将被发送到服务器。

问题

处理嵌入式关联的最佳方法是什么?

如果我将survey.get("questions")[any_index]传递给QuestionView,并且问题发生了变化,我必须在我的模型中手动搜索question.id并更新我的模型。这感觉不对。

如果我在QuestionsCollection中创建SurveyModel(这是否可能?)。然后我可以做一些事情,比如通过id从这个集合中取出Question,将它传递给视图,当我更改模型时,所有内容都会自动更新,但是我必须指定一个url如果事情得到更新,集合和骨干将向服务器发送单个问题。

关于如何以骨干方式做到这一点的任何建议?

4 个答案:

答案 0 :(得分:15)

在backbone.js中嵌入一对多关联的方法

我已经实现了@Sander的答案,只想发布一些代码:

class Survey extends Backbone.Model

  # Handles the Survey.questions association to parse stuff from the server
  parse: (resp) ->
    if @attributes?.questions?
      @attributes.questions.reset(resp.questions)
    else
      resp.questions = new QuestionsCollection(resp.questions)
    resp

  # Recollects Survey.questions
  toJSON: ->
    attributes = _.clone(@attributes)
    attributes.questions = attributes.questions.toJSON()
    attributes

然后我可以做类似的事情:

survey = Survey.get("my-id")
survey.questions.at(0).title = "First question"
survey.questions.at(1).title = "Second question"
survey.save()

哪个很舒服。

答案 1 :(得分:5)

你可以在SurveyModel中找到一个问题收集。

但你对这个被视为单个问题的问题是正确的(因为每个问题都应该有自己的ID,所以仍然可以在服务器上知道它属于哪个调查...)

然后解析你的json: 如果您手动构建集合和模型,则不会出现此问题,但如果要添加嵌套的JSON,则不会自动为模型创建子集合。你需要在重写的解析方法中指定这样的东西。

答案 2 :(得分:4)

我认为你甚至可以在建设中做到这一点

class Survey  extends Backbone.Model

initialize: ->
    @questions = new QuestionsCollection(@get('questions'))

此外,您可以普遍扩展模型以获取嵌套数据:

_.extend Backbone.Model::, deepToJSON: ->
  obj = @toJSON()
  _.each _.keys(obj), (key) ->
    obj[key] = obj[key].deepToJSON()  if _.isFunction(obj[key].deepToJSON)

  obj

_.extend Backbone.Collection::, deepToJSON: ->
  @map (model) ->
    model.deepToJSON()

答案 3 :(得分:0)

覆盖parse / toJSON是一个可行的解决方案。但需要注意的是,当通过集合获取对象时,parse方法中的“this”不是模型对象。然后会发生什么是调用parse并将结果传递给initialize。您可能需要“this”指向模型对象的原因是您要绑定集合上的事件。另一种方法是改写set方法。我提出了展示这种方法的a simple script on Github