Skip to content

Instantly share code, notes, and snippets.

@mpneuried
Created November 21, 2013 10:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mpneuried/7579199 to your computer and use it in GitHub Desktop.
Save mpneuried/7579199 to your computer and use it in GitHub Desktop.
Backbone collection extension to solve the problem of getting a model with eventually not exists within a collection. It also handles parallel fetches and distributes a single `.fetch()` to multiple requesters.
###
EXAMPLE USAGE
testColl = new Backbone.Collection.Extended()
# PROMISE USAGE
# define handlers
fnSuccess = ->
console.log( "SUCCESS", arguments )
return
fnError = ->
console.log( "ERROR", arguments )
return
# get model
testColl.getOrFetchId( 13 ).then( fnSuccess, fnError )
# force a fetch
testColl.getOrFetchId( 42, true ).then( fnSuccess, fnError )
# CALLBACK USAGE
# get model
testColl.getOrFetchId( 13, ( (err, model)->
console.log( "CALLBACK 42 A", arguments )
) )
# force a fetch
testColl.getOrFetchId( 42, true ( (err, model)->
console.log( "CALLBACK 42 B", arguments )
) )
###
class Backbone.Collection.Extended extends Backbone.Collection
###
## getOrFetchId
`collection.getOrFetchId( id, force, cb )`
Get a single model by id an fetch it from the server if it not exists within the collection.
It also handles parallel calles of a id and distribute a single fetch to multiple requesters
@param { String|Number } id The id to get
@param { Boolean } force Force a fetch
@param { Function } cb Callback function
@return { Promise } Instead of the callback you can use a promise syntax
@api public
###
getOrFetchId: ( id, force, cb )=>
# initialize variable to store running calls
@_runningGetOrFetchIds or= {}
# fix the arguments
if _.isFunction( force )
cb = force
force = false
# general success handler
fnSuccess = ( model )=>
# add the model to the collection if not exists
@add( model, silent: true ) if not @get( id )
# answer the callback if needed
cb( null, model ) if cb?
# resolve the current open promise and clear it
if @_runningGetOrFetchIds[ id ]?
@_runningGetOrFetchIds[ id ].resolve( model )
@_runningGetOrFetchIds[ id ] = null
return
# general error handler
fnError = ( model, resp )=>
# answer the callback if needed
cb( resp or model ) if cb?
# reject the current open promise and clear it
if @_runningGetOrFetchIds[ id ]?
@_runningGetOrFetchIds[ id ].reject( resp )
@_runningGetOrFetchIds[ id ] = null
return
# check if a fetch for this requested id is allready running
if @_runningGetOrFetchIds[ id ]?
# reuse the running promise and answer the requester with the currently running promise
if cb?
@_runningGetOrFetchIds[ id ].then( fnSuccess, fnError )
return @_runningGetOrFetchIds[ id ]
# create a new promise
deferred = @_runningGetOrFetchIds[ id ] = $.Deferred()
# check if model allready exists
_model = @get( id )
# on force = true or missing model fetch the model
if force or not _model?
# create a new model to fetch
_data = {}
_data[ @model.prototype.idAttribute ] = id
_model = new @model( _data )
# run fetch and pass the results to the general handlers
_model.fetch( success: fnSuccess, error: fnError )
else
# resolve the promise immediately id the model exists
deferred = @_runningGetOrFetchIds[ id ] = $.Deferred()
fnSuccess( _model )
return deferred.promise()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment