NgActiveResource
Connects business objects and REST web services for Angular.js
Install / Use
/learn @FacultyCreative/NgActiveResourceREADME
ActiveResource for Angular.js
ActiveResource provides a Base class to make modelling with Angular easier. It provides associations, caching, API integration, validations, and Active Record pattern persistence methods.
Installation:
Download
With Bower
If you have bower install just run
bower install ngActiveResource --save-dev
Manually
To manually download head over to the latest release and hit the big 'source code' button.
Install
Once downloaded you'll find everything you need in the /dist directory, include either file and add it as a dependency in your module.
angular.module('app', ['ActiveResource']);
Note: Don't forget to include lodash.js before active-resource.js.
Installation:
In your bower.json:
"ngActiveResource": "latest"
Simple:
Say you want a form to add comments to a post:
<form ng-submit="comment.$save()">
<input ng-model="comment.text">
<input type="submit">
</form>
<div ng-repeat="comment in post.comments">
{{comment.text}}
</div>
In your controller, all you have to setup is something like this:
Post.find(postId).then(function(response) {
$scope.post = response;
$scope.comment = $scope.post.comments.new();
Comment.after('$save', function() {
$scope.comment = $scope.post.comments.new();
});
};
You don't even have to tell ng-repeat to load in the new comment. The new
comment will already be added to the post by association. Simply tell the
comment object on the scope to clear, so that the user can enter another
comment.
Writing a Model:
Create an Angular factory or provider that relies on ActiveResource:
angular.module('app', ['ActiveResource'])
.factory('Post', ['ActiveResource', function(ActiveResource) {
function Post(data) {
this.number('id');
this.string('title');
this.string('subtitle');
this.computedProperty('fullTitle', function() {
return this.title + this.subtitle;
}, ['title', 'subtitle']);
this.hasMany('comments');
this.belongsTo('author');
};
Post.inherits(ActiveResource.Base);
Post.api.set('http://api.faculty.com');
Post.dependentDestroy('comments');
return Post;
});
The model is terse, but gains a lot of functionality from ActiveResource.Base.
It declares a has-many relationship on Comment, allowing it to say things like:
var post = Post.new({ title: "My First Post" });
var comment = post.comments.new({ text: "Great post!" });
The new comment will be an instance of the class Comment, which will be defined in its own model.
It also declares a belongs-to relationship on Author. This allows it to say things like:
var author = Author.new();
comment.author = author;
comment.$save().then(function(response) { comment = response; });
This will also cause author.comments to include this instance of Comment.
Post also declares a dependent-destroy relationship on comments, meaning:
Post.$delete().then(function(response) { post = comment = response; });
expect(post).not.toBeDefined();
expect(comment).not.toBeDefined();
expect(Post.find({ title: "My First Post" }).not.toBeDefined();
expect(Comment.find({ text: "Great post!" }).not.toBeDefined();
This means the post and its comments have been deleted both locally and from the database.
The astute reader will notice methods prefaced with $ are interacting with an
API. The API calls are established in the model definition under
Post.api.set().
Computed Properties:
Following the syntax of Ember.js' computed properties, you can create properties that auto-magically update with or without Angular's two-way binding:
function TShirt() {
this.number('price');
this.computedProperty('salePrice', function() {
return this.price - (this.price * 0.2);
}, 'price');
this.computedProperty('superSalePrice', function() {
return this.price - this.salePrice;
}, ['price', 'salePrice']);
}
Establish Associations:
A has many association can be setup by naming the field. If the field name is
also the name of the provider that contains the foreign model, this is all you
have to say. If the name of the provider is different, you can set it explicitly
via the provider option:
this.hasMany('comments', { provider: 'CommentModel' });
Foreign keys will also be intuited. For instance:
this.belongsTo('post');
Expect the model to define a post_id attribute mapping to the primary key of
the post to which it belongs. If the foreign key is different, you can set it
explicitly:
this.belongsTo('post', { foreign_key: 'my_post_id' });
Any number of options can be set on the association:
this.belongsTo('post', { provider: 'PostModel', foreign_key: 'my_post_id' });
Methods:
ActiveResource adds two types of methods to your models and instances:
-
API-updating methods. These are prefaced with
$, such as$create,$save,$update, and$delete, and are the 'unsafe' methods in a RESTful API (POST, PUT, and DELETE). These methods will call the API using the URLs you've set as ModelName.api.createURL, ModelName.api.updateURL, and ModelName.api.deleteURL. The api.set method sets default API URLs for you, but you can override these defaults by setting them explicitly. -
Local-instance creating and finding methods. These include
new,find,where,all, andupdate.newcreates a new instance of a model on the client, andupdateupdates that instance without issuing a PUT request.findwill attempt to find local instances in the model's client-side cache before issuing a GET request, andwhereandallwill always issue a GET request to ensure it has all instances of a model that match given terms. These are the 'safe' methods in a RESTful API (GET).
Query Interface:
Getting Set Up:
Best case scenario: You have an API that adheres to ActiveResource's RESTful convention. Here's that convention:
| HTTP Verb | CRUD | Path | Action | Used To | | --------- |:--------:|:----------:|:------:|:--------------------- | | GET | Retrieve | /users | index | Display a list of all users, or all users filtered by querystring | | GET | Retrieve | /users/:id | show | Display a specific user, found by params or querystring | | POST | Create | /users | create | Create a user | | PUT | Update | /users/:id | update | Update a specific user | | DELETE | Destroy | /users/:id | destroy| Delete a specific user |
If you do have an API that follows these conventions, hooking it up to ActiveResource is as easy as:
Post.api.set('http://api.faculty.com');
Optionally, you can specify a format for your requests:
Post.api.set('http://api.faculty.com').format('json');
Many APIs are set up to respond with specified data types if they are specified in the URLs. A request like:
Post.find({id: 1});
Will send the request:
http://api.faculty.com/posts/1.json
If you need to override specific URLs:
Post.api.indexURL = 'http://api.faculty.com/list-all-the-users';
Post.api.showURL = 'http://api.faculty.com/show-me-user';
Post.api.deleteURL = 'http://api.faculty.com/show-me-user/:param.json';
Parameterized URLS versus Query Strings:
To signal to ActiveResource that you want it to replace parameters in your URL, simply type them following a colon:
Post.api.showURL = /posts/:id
Post.api.showURL = /posts/:_id // MongoDB
The parameters themselves will be replaced:
Post.find({ id: 1 });
>> http://faculty.api.com/posts/1
If no parameters are not provided or your request utilizes parameters that are not specified in the search URL, then a querystring will be generated:
Post.findURL = 'http://api.faculty.com/posts/:id';
Post.find({author_id: 1});
// 'http://faculty.api.com/posts/?author_id=1'
The indexURL is intended as a search URL. It is not expected to be
parameterized (though you can parameterize it). By default, that means it will
search using a querystring:
Post.api.set('http://faculty.api.com').format('json');
Post.where({author_id: 1});
// 'http://faculty.api.com/posts.json/?author_id=1'
Find:
Post.find({ title: 'My Great Post' });
find is used to retrieve a single instance of a model. It is a method akin to
the show action in a RESTful API. Therefore, it first attempts to use the showURL, and
will fall back on the indexURL if a showURL is not defined.
find returns only the first instance it finds. If the instance is already
stored into the browser's cache, it will not make a backend request. To force a
backend request, you can add the forceGET request option:
Post.find({ title: 'My Great Post' }, { forceGET: true });
By default, find will also eagerly load a single level of associations. If a Post has many comments, and we find a post, then its comments will be loaded as well, but the comments will not load their authors, or other comment-based associations. To load associations' associations, pass the option:
{ overEager: true }
Warning: Over-eager loading is potentially very resource-intensive, and will often pull down sizeable portions of the database.
To lazily load as
Related Skills
node-connect
347.6kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
108.4kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
347.6kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
347.6kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
