最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Backbone.js and Embedded One-To-Many Associations - Stack Overflow

programmeradmin4浏览0评论

The App Layout

I am building an App, where one can create surveys. Every survey has multiple questions. I am embedding the questions into the survey model (with embeds_many in Mongoid), so a survey may look like this:

{
  "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!"]
    }
  ]
}

Now, there is also a survey editor which consists of a SurveyView, which displays the survey and lists the questions. If I click on a single question, a QuestionView will pop up, where I can edit the question. And when I am satisfied with my survey and I click save, the SurveyModel will be sent to the server.

The problem

What is the best way to handle the embedded association?

If I pass survey.get("questions")[any_index] to the QuestionView, and the question gets changed, I have to manually search for the question.id in my model and update my model. This feels wrong.

If I create a QuestionsCollection in my SurveyModel (is this even possible?). Then I can do things like fetching a Question out of this collection by id, pass it to the view and when I change the model, everything will get updated automatically, but I have to specify an url in the collection, and backbone will send single questions to the server, if things get updated.

Any suggestion on how to do this the backbone way?

The App Layout

I am building an App, where one can create surveys. Every survey has multiple questions. I am embedding the questions into the survey model (with embeds_many in Mongoid), so a survey may look like this:

{
  "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!"]
    }
  ]
}

Now, there is also a survey editor which consists of a SurveyView, which displays the survey and lists the questions. If I click on a single question, a QuestionView will pop up, where I can edit the question. And when I am satisfied with my survey and I click save, the SurveyModel will be sent to the server.

The problem

What is the best way to handle the embedded association?

If I pass survey.get("questions")[any_index] to the QuestionView, and the question gets changed, I have to manually search for the question.id in my model and update my model. This feels wrong.

If I create a QuestionsCollection in my SurveyModel (is this even possible?). Then I can do things like fetching a Question out of this collection by id, pass it to the view and when I change the model, everything will get updated automatically, but I have to specify an url in the collection, and backbone will send single questions to the server, if things get updated.

Any suggestion on how to do this the backbone way?

Share Improve this question edited Feb 12, 2012 at 12:13 iblue asked Feb 11, 2012 at 21:52 iblueiblue 30.4k20 gold badges92 silver badges129 bronze badges 1
  • Could you please paste the final code in javascript? not the coffeescipt. thanks. – Joe.wang Commented Mar 1, 2013 at 2:04
Add a comment  | 

4 Answers 4

Reset to default 15

The way to do embedded one-to-many associations in backbone.js

I have implemented the answer from @Sander and just wanted to post some code:

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

Then I can do stuff like:

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

Which works quite comfortable.

you can most certainly have a questionsCollection inside your SurveyModel.

but you are right on the question being seen as a single question (since every question should have his own ID, it might still be possible to know on the server which survey it belongs to...)

then there is the parsing of your json: if you are building your collection's and models manually you won't have this issue, but if you would add your nested JSON it will not automatically create a sub collection to your model. you would need to specify such things in an overridden parse method.

I think you can even do that at contruction

class Survey  extends Backbone.Model

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

Also you can extend model universally to get the nested data:

_.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()

Overriding parse/toJSON is a workable solution. One gotcha to be aware of though is that "this" in the parse method is not the model object when the object is fetched via a collection. What happens then is that parse is invoked and the result is passed to initialize. The reason you may need "this" to point to the model object is if you want to bind events on the collection. An alternative approach is to override the set method instead. I put up a simple script on Github that showcases this approach.

发布评论

评论列表(0)

  1. 暂无评论