AngularJS custom model objects with methods?
Asked Answered
B

1

8

When you have a JSON $resource how can you cast the resulting objects into more specific objects once obtained?

For example, right now they come back as an Array of Objects, but I want them to come back as an Array of "Appointment" objects, so that I can have some methods on that Appointment object which would answer questions about that Appointment object. Ex: Does This Appointment have any services associated with it? Is This appointment in the morning or afternoon?

At first I thought transformResponse hook would work from ngResource, but that doesn't appear to work. The return from that is not the actual objects. Seems that with that function you can only modify the actual data prior to the JSON parsing.

Finally, I question if this is even a proper angularJS technique? Or should these helper methods just show up in a controller or some other module and accept the object to work upon? I just think its cleaner to have them wrapped up in the object, but I admit that I'm not very experienced in angularJS.

Bethlehem answered 18/8, 2013 at 15:19 Comment(0)
Y
22

If you're using a factory and want to add a function you can for example add the function to the prototype of the returned item (DEMO):

app.factory('Appointment', ['$resource', function($resource) {
  var Item = $resource('appointments.json',{/*bindings*/},{/*actions*/});

  Item.prototype.hasServices = function() {
    if(this.services.length > 0) return true;
    else return false;
  };

  Item.prototype.partOfDay = function() {
    if(this.time.split(':')[0] > 12) return "afternoon";
    else return "morning";
  };

  return Item;

}]);

And then access it on your resource in the controller:

$scope.appointments = Appointment.query({}, function() {
    console.log($scope.appointments[0].partOfDay())
});

Or directly in the view inside for example an ng-repeat:

{{appointment.partOfDay()}}

To answer your last question, I think the above solution is a proper angularjs technique. As soon as you have functions associated with a specific resource type it's in my opinion the best to directly append them to the respective resource object. Why should you create helper functions in the controller when you have to pass the resource as a parameter and additionaly the functions may be used in multiple controllers or scopes?!

Yoakum answered 18/8, 2013 at 16:19 Comment(9)
Thanks for the example Plunker. I guess I'm not really understanding how $resource is working when you are obtaining Arrays from the JSON service. When I debug things, its still setting a "Resource" object, but I assume that once actually obtained, it gets somehow set to the Appointment object? I have it working, but just want to understand how I got it working.Bethlehem
The factory is just called Appointment and it returns a standard resource object with additional functions added to its prototype.Yoakum
It's basically the same as when you write a basic function in plain js called Appointment which returns an object with some properties. This has not much to do with the requested json itself. As soon as the ajax request is finished the result gets appended to the resource object.Yoakum
Right, so we have a factory, which returns a $resource object with additional functions added to the resulting $resource object. So, I would think that those would be methods added to the $resource object returned (ie: in addition to query, get, post, etc). But somehow they are magically being applied to the resulting objects obtained via the objects returned form $resource.. Thats my confusion?Bethlehem
Every single appointment in the array is an instance of Appointment. Therefore they all contain the functions added with prototype. It's exactly the same as $save, $delete etc. In the default resource object. I think you should read a little bit about prototype in js.Yoakum
Got it. Makes sense now. It will never be a "Real" appointment object (ie: var Appointment = {}), but rather a resource object and will just have additional methods added to it via prototype (along with the standard $resource methods to save/delete the resource). I guess because I am dealing with read-only data, I wasn't needing the two-way functionality of $resource and had thought more like passing the JSON object returned to a fromJSON method of an real Appointment object. At that point I really wouldn't need $resource and could do that just via a angularJS service with $http, right?Bethlehem
You could but what would be the advantage?Yoakum
I don't think there would be, except you could handle things like nested objects (ie: array of services under an appointment could be their own prototypes).. But in this solution they would just be a new resource which makes more sense. Thanks again for your time to create the demo. Appreciate it.Bethlehem
How do you test these methods?Langton

© 2022 - 2024 — McMap. All rights reserved.