Back to Resources


Posted July 24, 2014

Adding Custom Methods to Data Models with Angular $resource


Sauce Labs software developer Alan Christopher Thomas and his team have been hard at work updating our stack. He shared with us some insight into their revised dev process, so we thought we’d show off what he’s done. Read his follow-up post below. Thanks for your great feedback to this post. Previously we examined three different approaches to modeling data in AngularJS. We've since incorporated some of your feedback, so we wanted to share that information here. One of our commenters made mention of a cleaner approach to adding custom methods to $resource models when our API response response allows it, using angular.extend(). In this implementation, we're imagining an API response that looks like this:

[ { "breakpointed": null, "browser": "android", "browser_short_version": "4.3", ... }, { ... } ... ]

Each of the response objects in the list is a "Job" that contains a whole lot of metadata about an individual job that's been run in the Sauce cloud. We want to be able to iterate over the jobs to build a list for our users, showing the outcome of each: "Pass," "Fail," etc. Our template looks something like this:

{{ job.getResult() }} {{ }}

Note the job.getResult() call. In order to get this convenience, however, we need to be able to attach a getResult() method to each Job returned in the response. So, here's what the model looks like, using Angular $resource:

angular.module('job.models', []) .factory('Job', ['$resource', function($resource) { var Job = $resource('/api/jobs/:jobId', { full: 'true', jobId: '@id' }); angular.extend(Job.prototype, { getResult: function() { if (this.status == 'complete') { if (this.passed === null) return "Finished"; else if (this.passed === true) return "Pass"; else if (this.passed === false) return "Fail"; } else return "Running"; } }); return Job; }]);

Note that since each resulting object returned by $resource is a Job object itself, we can simply extend Job.prototype to include the behavior we want for every individual job instance. Then, our controller looks like this (revised from the original post to make use of the not-so-obvious promise):

angular.module('job.controllers', []) .controller('jobsController', ['$scope', '$http', 'Job', function($scope, $http, Job) { $scope.loadJobs = function() { $scope.isLoading = true; var jobs = Job.query().$promise.then(function(jobs) { $ = jobs; }); };

The simplicity of this example makes $resource a much more attractive option for our team's data-modeling needs, especially considering that for simple applications, custom behavior isn't incredibly unwieldy to implement. - Alan Christopher Thomas, Software Developer, Sauce Labs

Jul 24, 2014
Share this post
Copy Share Link
© 2023 Sauce Labs Inc., all rights reserved. SAUCE and SAUCE LABS are registered trademarks owned by Sauce Labs Inc. in the United States, EU, and may be registered in other jurisdictions.