This angular module provide base model objects usable in your AngularJS application, designed like the Backbone models.
Just add angular-simple-model
in your bower.json
dependencies:
{
"dependencies": {
"angular-simple-model": "~0.3.0"
}
}
Then, run bower install
.
If you're using grunt-wiredep the JS file will be injected automatically by Grunt, else you'll have to add the JavaScript file:
<script type="text/javascript" src="bower_components/angular-simple-module/release/angular-simple-model.min.js"></script>
Everything is built on the Collection
and Model
factories. These classes provide a lot of methods that are common between your models and collections.
A collection is quite no more than an array of models.
You have to require the angular-simple-model
module to be able to inject the provided factories:
angular.module('your-module', [
'dependency',
// ...
'angular-simple-model'
]);
To create your custom model, you just have to extend the Model
"class" with the extend
method which take one or two parameters.
The parameter is the instance methods and attributes while the second (optional) is the class methods.
angular.module('your-module')
.factory('Task', function(Model) {
return Model.extend({
baseUrl: '/path/to/your/api/task/{id)'
});
});
angular.module('your-module')
.factory('TaskCollection', function(Collection, Task) {
return Collection.extend({
baseUrl: '/path/to/your/api/tasks',
model: Task
});
});
You can now inject your models and collections where you want, in your services, controllers...
Here's a task list controller example:
angular.module('your-module')
.controller('TaskListCtrl', function($scope, TaskCollection) {
var tasks = new TaskCollection();
$scope.isLoading = true;
tasks.fetch().then(function(tasks) {
$scope.tasks = tasks.attributes;
}, function(error) {
$scope.error = 'Unable to fetch tasks';
})['finally'](function() {
$scope.isLoading = false;
});
});
Then, you're show/update controller could be:
angular.module('your-module')
.controller('TaskCtrl', function($scope, $routeParams, Task) {
// Get your task ID
var taskId = $routeParams.id;
// Create the task model
var task = new Task({id: taskId});
// Fetch the task
$scope.isLoading = true;
task.fetch().then(function(task) {
$scope.task = task.attributes;
}, function(error) {
$scope.error = 'Unable to fetch task #'+taskId;
})['finally'](function() {
$scope.isLoading = false;
});
// Add an `save` method callable form your view
$scope.save = function() {
task.save().then(function() {
alert('Saved !');
}, function() {
alert('An error appeared while saving task');
});
};
});
As you can see, the main point is that you're attaching the attributes
attribute of the instance to the scope which is the object (or array for collections) that make your model usable as a simple object at the view side. Using ng-model
or any other binding way you're able to update the model content without accessing directly the instance methods such as save
, fetch
, etc...
And the power come from these instance methods: let's say you're Task
model has a name
and a date
attribute. You may fetch this date from the API encoded as an ISO-6801 but want to use it in your AngularJS application as a Date
object.
You just have to override the prepare
and parse
methods of your object the make this transformations:
angular.module('your-module')
.factory('Task', function(Model) {
return Model.extend({
baseUrl: '/path/to/your/api/task/{id)',
// Will be called when the server response is received
parse: function() {
// Get attributes from the "native" way by calling super
var attributes = Model.prototype.parse.apply(this, arguments);
// Create the `Date` object
attributes.date = new Date(attributes.date);
return attributes;
},
// Will be called when creating the data sent to the server
prepare: function(attributes) {
return {
name: attributes.name,
date: attributes.date.toISOString()
}
}
});
});
Note: check the EC5 toISOString
method support to use it in production.
By creating custom instance methods, you can for instance create a method on the Task
model to get its related issues easily:
angular.module('your-module')
.factory('Task', function(Model, IssueCollection) {
return Model.extend({
baseUrl: '/path/to/your/api/task/{id)',
getIssues: function() {
return new IssueCollection([], {
url: this.url()+'/issues'
});
})
};
});
You can then fetch the task issues:
var task = new Task({id: taskId});
task.getIssues().fetch().then(function(issues) {
$scope.issues = issues.attributes;
});
Note: this assumes that you previously created an IssueCollection
class.
Tests can be run directly with npm:
npm test