So personally, I didn't muck around with $resource at all. I basically
over-engineered the whole thing, and defined my own Model class. That model
constructor has some data caches defined and a constructor-level function
called defineField, which attaches get and set functions for that field on
the prototype. The generic get is something like: "Does
this.$cache.$promise exist? if not, return the default field value (empty
string, empty array, based on the field type) and run the $http.get, and in
the .then block fill out the $cache.field.value. If the promise exists, and
the $cache.field.value exists, just return that.
This is, as far as I can tell, kind of like how ngResource works, but is
one of those things I Did Myself because I wanted to Figure Stuff Out.
What this effectively does is lets me create objects like $scope.rootUser =
User.find(1) without needing to deal with promises in the controller, and
also not do things like preload All Users (or whatever) when I say
User.all(), but instead only do a server hit and data inflation when I
actually need the object (it gets referenced or used on the screen). I also
expose a $promise, so in the event of concurrency-important stuff, I can
make sure the object is fully loaded before doing anything. The downside of
course is that it's harder to actually create a whack of objects from one
XHR request that returns a list. I'm working on getting that to be better
in the near future (basically just filling out the data in the storage and
putting an already-resolved promise in the $promise field.
Here's the relevant code from Model (I can subclass Model as my specific
data type using the coffeescript class notation), which is part of a
library I'm eventually releasing under MIT license, so you can feel free to
use this as you see fit if it's helpful. But it probably isn't.
@defineField: (def)->
@$fields[@$type] ?= {}
throw new Error("Duplicate type definition #{def.name}") if
@$fields[@$type][def.name]?
@$fields[@$type][def.name] = def
@$fields[@$type][def.name].type ?= 'string'
@$fields[@$type][def.name].responseField ?=
@$fields[@$type][def.name].endpoint
Object.defineProperty @prototype, def.name,
get: ->
@$getValue @constructor.$fields[@$type][def.name]
set: (v)->
@$setValue @constructor.$fields[@$type][def.name], v
$getValue: (field)->
if field.type == 'sideload'
@$cache[field.name] ?= {values: []}
unless @$cache[field.name]['$promise']
@$cache[field.name]['$promise'] =
field.fetch("#{@$url}/#{field.endpoint}") #fetch should resolve to an
array of Models
@$cache[field.name]['$promise'].then (ary)=>
values = field.parse(ary[field.responseField])
# console.log ary if field.name == 'replies'
# console.log values if field.name == 'replies'
@$cache[field.name].values.map (val, index)=>
@$cache[field.name].values.splice(index,1) unless
values.some (v)-> v.id == val.id
values.map (value)=>
@$cache[field.name].values.push(value) unless
@$cache[field.name].values.some (v)->v.id == value.id
@$cache[field.name].values
else if @$id?
@$read()
if @$cache[field.name]?
@$cache[field.name]
else if field.uninitialized?
field.uninitialized.call @
else
undefined
$setValue: (field, val)->
if field.type != 'sideload' #cannot set a sideload value
if @$id?
@$read().then =>
@$cache[field.name] = val
else
if @$cache['$promise']?
#case where we are midflight in the create() call
@$cache['promise'].then =>
@$cache[field.name] = val
else
@$cache[field.name] = val
On Thu, Jul 24, 2014 at 8:51 AM, Michael Schuerig <[email protected]
> wrote:
> On Wednesday 09 July 2014 06:19:39 Chris Scribner wrote:
> > As an example, this code seems to work for things returned by
> > $resource:
> >
> > $scope.things = Model.getThings({ property: '123' });
> >
> > However, this seems to be the way to do it with promises now:
> >
> > Model.getThings({ property: '123' }).$promise.then((things) => {
> > $scope.things = things;
> > });
> >
> > Accessing .$promise directly feels really weird though. I also don't
> > understand why $resource returns an array containing $promise and
> > $resolved instead of just returning the promise (maybe it deals with
> > getting the automatic unwrapping behavior?). I tried returning a
> > similar structure from one of my own methods and it did not get
> > automatically unwrapped...
> >
> > Can anyone help explain the thinking around this and how we should use
> > it?
>
> I'm plainly lacking the experience to answer this with any certainty,
> but as there are no other takers... I've rummaged around a bit in the
> angular sources what seems to be happening is that your Model.getThings
> immediately returns an empty object (or collection). When the http
> request completes and the associated promise is resolved, the original
> object is updated. Then the $digest loop is triggered, which detects the
> change and updates the view accordingly.
>
>
> https://github.com/angular/angular.js/blob/master/src/ngResource/resource.js#L565-L596
> https://github.com/angular/angular.js/blob/g3_v1_2/src/ng/http.js#L1010
>
> Michael
>
> --
> Michael Schuerig
> mailto:[email protected]
> http://www.schuerig.de/michael/
>
> --
> You received this message because you are subscribed to the Google Groups
> "AngularJS" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to [email protected].
> To post to this group, send email to [email protected].
> Visit this group at http://groups.google.com/group/angular.
> For more options, visit https://groups.google.com/d/optout.
>
--
You received this message because you are subscribed to the Google Groups
"AngularJS" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/angular.
For more options, visit https://groups.google.com/d/optout.