When creating an object oriented CRUD operation, often you’ll have a case where an object will have children that are independently managed resources. Each child is simply associated to the parent, but when editing the entire object it’s likely that a better guest experience calls for one screen, rather than many. The editor shouldn’t have to care if they’re updating one or many objects at once.
If the parent is dependent on the children objects to complete their operations before the parent can complete theirs, then you’ll have to create a dependency tree. Each child would likely have other dependents, and would thusly need to wait until their dependencies are saved before continuing up the tree.
We cannot simply start with the last child process and work our way back up, this could result in orphaning the children that are in the outer-most parallel branches of the tree. We’ll need to begin from the parent, and recursively work our way down the branches until we’ve resolved each child’s process. Using the composite pattern, we can treat each child the same way as a single instance of an object, and in this case each one is an ngResource.
app.service 'resourceService', ['$resource', '$rootScope', '$q', ($resource, $rootScope, $q)-> $rootScope.resources = {} resourceService = newResource : (tag, url, paramDefaults = {}, actions = {}, options = {})-> if !$rootScope.resources[tag] actions = _.extend actions, update : method : 'PUT' resource = $resource(url, paramDefaults, actions, options) $rootScope.resources[tag] = resourceService.extendResource resource $rootScope.resources[tag] autoQuery : (tag, url, paramDefaults = {}, actions = {}, options = {})-> resourceService.newResource(tag, url, paramDefaults, actions, options).query() getResource : (tag)-> $rootScope.resources[tag] convertToResource : (obj, resource)-> if Array.isArray obj obj = (item = resourceService.convertToResource item, resource for item in obj) else proto = Object.create resource.prototype obj = _.extend proto, obj obj = resourceService.extendResource obj obj extendResource : (resource)-> if Array.isArray resource resource = (r = resourceService.extendResource r for r in resource) else # Since JS won't do this for me, let's create a hash for each resource. resource._hash = Math.random().toString(36).substring(7) # Create a child for this resource resource._children = [] resource.getResourceId = ()-> @_hash resource.addChild = (child)-> # locate the hash and remove it if applicable hash = child.getResourceId() @_children = _.reject @_children, (child)-> return child.id == hash @_children.push id : hash resource : child resource.setCallbacks = (@successCallback, @errorCallback, @notifyCallback)-> resource resource.resolve = ()-> children = @_children promises = [] promises.push $q.when child.resource.resolve() for child in children combined = $q.all promises parent = @ combined.then(()-> parent._children = []) .then(@successCallback, @errorCallback, @notifyCallback) # return the resource resource resourceService ]