Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to build deeply nested models in Backbone.js v0.5

Tags:

backbone.js

Assuming each A has 0 or more B and each B has 0 or more C items. How would one present this relationship in Backbone.js (v0.5). I would like to have urls like /A/a/B/b/C/c. The following code is in coffeescript. I am confused, how to set the url variables in the follow code.

class As extends Backbone.Collection  
   url: "/A"   
   model: A

class A extends Backbone.Model  
  initialize: ->
    @Bs = new Bs()
    @Bs.parent=@
    @Bs.url="/A/#{@id}"

class Bs extends Backbone.Collection    
    model: B

class B extends Backbone.Model  
    initialize: ->
    @Cs = new Cs()
    @Cs.url = ??? # => /A/a/B/b/C/   
    @Cs.parent=@

class Cs extends Backbone.Collection  
    model: C

class C extends Backbone.Model
    url: #?? url => /A/a/B/b/C/c   
like image 996
Ali Salehi Avatar asked Jul 05 '11 10:07

Ali Salehi


1 Answers

I would not create nested URL's unless you really have a good case for it. Each resource can be defined by a resource name and an id. The relationship between the objects is internal.

http://foo.com/a/:id.json
http://foo.com/b/:id.json
http://foo.com/c/:id.json

That being said lots of hits to the server to pull out nested objects is not really ideal. You are better having a single resource that returns nested json

http://foo.com/a/:id.json

For example the data I get back from my server looks like

{
  "id": 372,
  "context": "office_work",
  "date_of_entry": "2011-7-05 15:22:00",
  "blood_glucose_measurement": 98,
  "food": {
    "exchanges": "98",
    "list": "burger fries"
  },
  "exercise": {
    "duration": "28",
    "list": "running shopping"
  }
}

The sub nodes are assembled by a custom controller that takes the individual db records and makes a tree of data.

However you are now in trouble because backbone.js natively only supports flat structures. I've made some modifications to the basic Backbone.Model to support processing tree like structures.

I'll paste it here if it might be of use to you.

#= require jquery
#= require underscore
#= require backbone
#
class RailsModel extends Backbone.Model

  initialize: (attributes) ->
    data = {}

    for k,v of @attributes
      if v.constructor.name == "Object"
        data[k] = new RailsModel(v)

    @set data, {silent: true}

  get: (field)->
    val  = @
    first =  true
    for p in field.split('/')
      if first
        val = super(p)
      else
        # This allows returning *undefined* rather
        # than an exception if the parent of a deeply
        # nested node does not exist.
        val = if val? then val.get(p) else undefined
      first = false
    val

  # Allow heirarchical setting of objects
  #
  # Example
  #
  # model.set_field('root/child', 10)
  #
  # Will create the path if it does not exist
  set_field: (field, value, silent=false)->
    path = field.split('/')

    node = undefined
    val  = @
    for p in field.split('/')
      node = val
      val = node.get(p)
      if not val?
        data = {}
        val = new RailsModel
        data[p] = val
        node.set data

    data = {}
    data[p] = value
    node.set data

    if not silent and /\//.test(field)
      @trigger("change:#{field}", @model, value)
      @trigger("change", @model)

window.RailsModel = RailsModel

You can use it like

model = new RailsModel
model.url = "/data"
model.fetch()
model.get('excercise/duration')
model.set_field('excercise/duration', 25)

The last line will trigger an event "change:excercise/duration"

like image 171
bradgonesurfing Avatar answered Nov 19 '22 10:11

bradgonesurfing