Skip to content

Instantly share code, notes, and snippets.

@therabidbanana
Created August 9, 2012 16:26
Show Gist options
  • Save therabidbanana/3305643 to your computer and use it in GitHub Desktop.
Save therabidbanana/3305643 to your computer and use it in GitHub Desktop.

Dtime.View is like CompositeView from Backbone on Rails book.

Observer from Backbone on Rails - call bindTo instead of @model.on, then unbindFromAll to handle unbinding automatically. The composite view keeps track of children and calls unbindFromAll for all children.

class Dtime.View extends Backbone.View
# Call cleanup before removing completely,
# unbind events from this and all children
leave: ->
@cleanup?()
@unbindFromAll()
@remove()
@_leaveChildren()
@_removeFromParent()
cleanup: ->
@$el.unbind("click", @debugClick)
render: ->
@attach()
@el
debugClick: (e)=>
# Just register interest, pass on event
if e.shiftKey && window.rails_env != "production"
window.debug ?= _([])
window.debug.push @
console.log "var debug.last() = ", window.debug.last()
e.preventDefault()
true
else
true
attach: ->
@children ||= _([])
@delegateEvents()
@attachSubviews(@el)
@$el.data('attached_view', @)
@$el.bind("click", @debugClick) unless window.rails_env == 'production'
@
setElement: (el)->
$(el).data('attached_view', @)
super(el)
constructView: (el, include_el = false)->
return $(el).data('attached_view') if $(el).data('attached_view')?
data = $(el).data()
key = JSON.stringify(data)
@loadedViews ?= {}
# Attach if already loaded
if @loadedViews[key]?
val = @loadedViews[key]
$(el).replaceWith(val.el)
return val
name = data.view
data.el = $(el) if include_el
klass = Dtime.Views[name]
if klass
val = new klass(data)
@loadedViews[key] = val
@attachChild(val)
return val
else
throw "Tried to build non-existent class #{name}"
attachSubviews: (el)->
parent = @
$(el).removeClass('attach_view')
$('.attach_view', el).filter ->
$(@).parents('.attach_view').length < 1
.each ()->
view = parent.constructView(@, true)
view.attach()
# Attaches a child without rendering
attachChild: (view)->
view.parent = this
@children ||= _([])
@children.push(view)
# Renders a child view and adds it to the list of children - does
# nothing to attach the view to the dom - use renderChildInto if this is
# needed.
renderChild: (view)->
@attachChild(view)
view.render()
# Renders a child and replaces a specific element with the new
# view.el
renderChildInto: (view, replace_el)->
@renderChild(view)
@$(replace_el).replaceWith(view.el)
appendChild: (view, replace_el)->
@renderChild(view)
@$el.append(view.el)
# Calls leave on all subviews
_leaveChildren: ->
@children?.chain().clone().each (view)->
view.leave?()
# Alerts parent that this view is leaving,
# so that it can be removed from children list
_removeFromParent: ()->
@parent?._removeChild(this)
# Removes child from list of children
# called when a child does a "leave" event.
_removeChild: (view)->
index = @children.indexOf(view)
@children.splice(index, 1)
# Attach views to existing dom elements that have class "attach_view"
window.attachViews = _.once ->
$('.attach_view').filter ->
$(@).parents('.attach_view').length < 1
.each ()->
viewname = $(@).data('view')
data = $(@).data()
data.el = @
view = new Dtime.Views[viewname](data)
view.attach()
$(()->
attachViews()
)
#= require ./view
class Dtime.Backbone.Observer
bindToModel: (event, callback) ->
source = @model
@bindTo(source, event, callback)
bindTo: (source, event, callback) ->
source.bind(event, callback, this)
this.bindings = this.bindings || []
this.bindings.push({ source: source, event: event, callback: callback })
unbindFromAll: () ->
_.each(this.bindings, (binding) ->
binding.source.unbind(binding.event, binding.callback);
)
this.bindings = []
_.extend(Dtime.Backbone.View::, Dtime.Backbone.Observer::)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment