Skip to content

Instantly share code, notes, and snippets.

@laurencer
Created January 25, 2013 12:37
Show Gist options
  • Save laurencer/4634135 to your computer and use it in GitHub Desktop.
Save laurencer/4634135 to your computer and use it in GitHub Desktop.
Enables mutator support (ala Backbone.Mutators) for Backbone-NestedModel.
# Written by Laurence Rouesnel (laurencer)
# Based on https://github.com/asciidisco/Backbone.Mutators
class Backbone.NestedModelWithMutators extends Backbone.NestedModel
constructor: ->
if _.isFunction(@mutators) then @mutators = @mutators()
super(arguments...)
get: (attr) =>
mutator = @mutators[attr]
# Exit early if no mutator exists.
return super(attr) if not mutator?
# Check if this is a mutator property.
return mutator.call(this) if _.isFunction(mutator)
# Check for a deeper nested getter mutation.
return mutator.get.call(this) if _.isObject(mutator) and _.isFunction(mutator.get)
# No mutator so invoke default.
return super(attr) if not mutator?
set: (key, value, options) =>
# Normalize the style of setter (object vs key-value)
if _.isObject(key) or key is null
attrs = key
options = value
else
attrs = {}
attrs[key] = value
# Determine whether an update is to a mutator or plain property
anyPlainUpdates = false
plainUpdates = {}
anyMutatorUpdates = false
mutatorUpdates = {}
for key, value of attrs
mutator = @mutators[key]
if mutator? and _.isFunction(mutator?.set)
mutatorUpdates[key] = value
anyMutatorUpdates = true
else
plainUpdates[key] = value
anyPlainUpdates = true
# The return value
ret = false
# Apply the mutator updates.
if anyMutatorUpdates
for key, value of mutatorUpdates
mutator = @mutators[key]
ret = ret || mutator.set.call(@, key, value, options, _.bind(super, @))
if anyPlainUpdates
ret = super(attrs, options) || ret
return ret
toJSON: =>
attributes = super()
for key, mutator of @mutators
newValue = if _.isFunction(mutator)
mutator()
else if _.isFunction(mutator?.get)
mutator.get()
path = Backbone.NestedModel.attrPath(key)
currentObj = attributes
for link, idx in path
if idx is path.length - 1
# If we are at the end of the path then set the value.
currentObj[link] = newValue
else
if currentObj[link]? and _.isObject(currentObj[link])
# If the object at the next link exists - set it to the current object.
currentObj = currentObj[link]
else if not currentObj[link]?
# If the object doesn't exist at the next link - create it.
currentObj[link] = {}
currentObj = currentObj[link]
else
# Break if it is not an object at this stage of the link.
console.log "Could not set mutator value in toJSON because non-object in path", {
mutatorKey: key
currentStep: path[0 ... idx]
newValue: newValue
currentValue: currentObj[link]
}
break
return attributes
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment