|
11 | 11 | **Angular Model** is a module that provides a simple way to bind client-side domain logic to JSON-based API resources. |
12 | 12 |
|
13 | 13 | By sticking to hypermedia design principles, Angular Model allows you to implement client applications that are cleanly decoupled from your server architecture. |
| 14 | + |
| 15 | +## Basic Usage |
| 16 | + |
| 17 | +In your AngularJS application, include the JavaScript: |
| 18 | + |
| 19 | +```html |
| 20 | +// your specific paths may vary |
| 21 | +<script src="node_modules/radify/angular-model.js"></script> |
| 22 | +``` |
| 23 | + |
| 24 | +In your app configuration, state a dependency on [Angular Model](https://github.com/radify/angular-model): |
| 25 | + |
| 26 | +```javascript |
| 27 | +angular.module('myApp', [ |
| 28 | + 'ur.model' |
| 29 | +]); |
| 30 | +``` |
| 31 | + |
| 32 | +## API documentation |
| 33 | + |
| 34 | +The source code is documented using the ngdoc standard using [gulp-ngdocs](https://www.npmjs.com/package/gulp-ngdocs/). A markdown version is browseable at [/docs](/docs/api.md). |
| 35 | + |
| 36 | +To generate documentation in HTML, run: |
| 37 | + |
| 38 | +```bash |
| 39 | +gulp ngdocs |
| 40 | +``` |
| 41 | + |
| 42 | +This will output docs into the `build/docs` directory. Then, using a server like `ws`, start a local web server: |
| 43 | + |
| 44 | +```bash |
| 45 | +cd build/docs |
| 46 | +npm install -g ws |
| 47 | +ws |
| 48 | +``` |
| 49 | + |
| 50 | +Then, you should be able to browse to http://localhost:8000 to view the API documentation for angular-model. |
| 51 | + |
| 52 | +## Configuration |
| 53 | + |
| 54 | +Here is a quick reference guide to all the configuration settings you can pass to the model() constructor, which is [documented in full in the API documentation](/docs/api.md). Each one is then described in detail later in this document, and in full in the source code in the `src` directory. |
| 55 | + |
| 56 | +Setting | Type | Description |
| 57 | +------- | ---- | ----------- |
| 58 | +url | string | API url that this model maps to |
| 59 | +defaults | object literal | Default values of attributes of instances of this model. Similar to properties in OOP. |
| 60 | +$instance | object literal | Instance methods available on each instance of this model. |
| 61 | +$class | object literal | Class methods available on this model. Similar to static methods in OOP. |
| 62 | +$collection | object literal | Collection |
| 63 | + |
| 64 | +### Defaults |
| 65 | + |
| 66 | +```javascript |
| 67 | +yourApp.config(function(modelProvider) { |
| 68 | + modelProvider.model('posts', { |
| 69 | + /** |
| 70 | + * @ngdoc object |
| 71 | + * @name yourApp.posts.defaults |
| 72 | + * @description |
| 73 | + * Configure the default attributes for instances of posts. |
| 74 | + * |
| 75 | + * This is similar to an OOP class, which has attributes with defaults, e.g. "public string foo = 'bar';" |
| 76 | + */ |
| 77 | + defaults: { |
| 78 | + name: '', // The name of the post |
| 79 | + published: false, // Whether the post has been released to the general public |
| 80 | + body: '', // Body text of this post |
| 81 | + logo: null, // The logo to show for this post |
| 82 | + author: 'John Doe'// Who wrote the post? |
| 83 | + } |
| 84 | + }); |
| 85 | +}); |
| 86 | +``` |
| 87 | + |
| 88 | +Here is an example of how the defaults get used: |
| 89 | + |
| 90 | +```javascript |
| 91 | +var post = model('posts').create({}); |
| 92 | +console.log(post.author); |
| 93 | +=> John Doe |
| 94 | +``` |
| 95 | + |
| 96 | +## Creating instances of your model |
| 97 | + |
| 98 | +You can use angular-model ad-hoc to construct object instances: |
| 99 | + |
| 100 | +```javascript |
| 101 | +// From defaults |
| 102 | +var post = model('posts').create({}); |
| 103 | + |
| 104 | +// Specifying fields |
| 105 | +var post = model('posts').create({ |
| 106 | + name: 'some post', |
| 107 | + body: "body of some body, it's just some body, you know?", |
| 108 | + author: 'Steve Davis' |
| 109 | +}); |
| 110 | + |
| 111 | +console.log(post.author); |
| 112 | +=> Steve Davis |
| 113 | +``` |
| 114 | + |
| 115 | +## Instance Methods |
| 116 | + |
| 117 | +angular-model instances have instance methods, similar to objects in the OOP world. |
| 118 | + |
| 119 | +### Default instance methods |
| 120 | + |
| 121 | +The following methods are available to every angular-model instance. |
| 122 | + |
| 123 | +Function | Description |
| 124 | +------- | ----------- |
| 125 | +$save | Persist an instance to the API |
| 126 | +$delete | Tell the API to delete an instance |
| 127 | +$reload | Refresh an instance of a model from the API |
| 128 | +$revert | Reset the model to the state it was originally in when you first got it from the API |
| 129 | +$exists | Checks whether an object exists in the API, based on whether it has an identity URL. |
| 130 | +$dirty | Returns boolean - true if a model instance has been modified, else false. Opposite of $pristine. |
| 131 | +$pristine | Returns boolean - true if a model instance has unmodified, else false. Opposite of $dirty. |
| 132 | +$related | Hydrates the $links property of the instance. $links are used so that an instance can tell the client which objects are related to it. For example, a `post` may have an `author` object related to it. |
| 133 | +$modified | Returns a map of the properties that have been changed |
| 134 | +$hasRelated | Does an instance have a relation of name `name`? |
| 135 | + |
| 136 | +> You can see full details of these methods in the [API documentation](/docs/api.md). |
| 137 | +
|
| 138 | +### Custom instance methods |
| 139 | + |
| 140 | +angular-model allows you to define instance methods on instances. This is similar to adding methods by extending a base class in the OOP world. |
| 141 | + |
| 142 | +```javascript |
| 143 | +yourApp.config(function(modelProvider) { |
| 144 | + modelProvider.model('posts', { |
| 145 | + // ... |
| 146 | + |
| 147 | + /** |
| 148 | + * @ngdoc object |
| 149 | + * @name yourApp.posts.$instance |
| 150 | + * @description |
| 151 | + * Instance methods that are callable on any individual instance of a post |
| 152 | + */ |
| 153 | + $instance: { |
| 154 | + /** |
| 155 | + * @ngdoc function |
| 156 | + * @name yourApp.posts.$logo |
| 157 | + * @description |
| 158 | + * If this post instance has a logo, return it, otherwise return a default string |
| 159 | + * |
| 160 | + * @return string Either the logo for this post, or a default logo |
| 161 | + */ |
| 162 | + $logo: function() { |
| 163 | + return this.logo || '/logos/default.png';. |
| 164 | + } |
| 165 | + } |
| 166 | + }); |
| 167 | +}); |
| 168 | +``` |
| 169 | + |
| 170 | +Example: |
| 171 | + |
| 172 | +```javascript |
| 173 | +var post = model('Posts').create({ |
| 174 | + logo: 'foo.png' |
| 175 | +}); |
| 176 | +console.log(post.$logo()); |
| 177 | +=> foo.png |
| 178 | +``` |
| 179 | + |
| 180 | +## Class methods |
| 181 | + |
| 182 | +### Default class methods |
| 183 | + |
| 184 | +The following methods are available statically to angular-model: |
| 185 | + |
| 186 | +Function | Description |
| 187 | +-------- | ----------- |
| 188 | +all | Make a request to the API, based on the `url` configuration setting |
| 189 | +first | Given a query, get the first model instance from the API |
| 190 | +create | Create a new instance of the model. Defaults come from the `defaults` configuration setting. |
| 191 | + |
| 192 | +> You can see full details of these methods in the [API documentation](/docs/api.md). |
| 193 | +
|
| 194 | +### Custom class methods |
| 195 | + |
| 196 | +angular-model allows you to define class methods on instances. This is similar to static methods in the OOP world. |
| 197 | + |
| 198 | +```javascript |
| 199 | +yourApp.config(function(modelProvider) { |
| 200 | + modelProvider.model('posts', { |
| 201 | + // ... |
| 202 | + |
| 203 | + /** |
| 204 | + * @ngdoc object |
| 205 | + * @name yourApp.posts.$class |
| 206 | + * @description |
| 207 | + * Class methods that are callable on the posts class, or any instance thereof. These |
| 208 | + * behave similarly to static methods in OOP languages. |
| 209 | + */ |
| 210 | + $class: { |
| 211 | + /** |
| 212 | + * @ngdoc function |
| 213 | + * @name yourApp.posts.roles |
| 214 | + * @description |
| 215 | + * Get an array of valid post types. |
| 216 | + * |
| 217 | + * @return array The valid types that a post can have. Array of strings |
| 218 | + */ |
| 219 | + types: function() { |
| 220 | + return ['announcement', 'article'] |
| 221 | + } |
| 222 | + } |
| 223 | + }); |
| 224 | +}); |
| 225 | +``` |
| 226 | + |
| 227 | +Example: |
| 228 | + |
| 229 | +```javascript |
| 230 | +console.log(model('Posts').types()); |
| 231 | +=> ['announcement', 'article'] |
| 232 | +``` |
| 233 | + |
| 234 | +## Collection methods |
| 235 | + |
| 236 | +You can use collection methods as well, so you can deal with a bunch of instances together. This allows you to have powerful and expressive methods on collections. |
| 237 | + |
| 238 | +### Default collection methods |
| 239 | + |
| 240 | +The following methods are available statically to angular-model: |
| 241 | + |
| 242 | +Function | Description |
| 243 | +-------- | ----------- |
| 244 | +add | Saves the `object` with `data` |
| 245 | +remove | Find `index` and delete it from the API, then remove it from the collection |
| 246 | + |
| 247 | +> You can see full details of these methods in the [API documentation](/docs/api.md). |
| 248 | +
|
| 249 | +### Custom collection methods |
| 250 | + |
| 251 | +```javascript |
| 252 | +yourApp.config(function(modelProvider) { |
| 253 | + modelProvider.model('posts', { |
| 254 | + // ... |
| 255 | + |
| 256 | + /** |
| 257 | + * @ngdoc object |
| 258 | + * @name yourApp.posts.$collection |
| 259 | + * @description |
| 260 | + * Methods that apply to a collection of posts together |
| 261 | + */ |
| 262 | + $collection: { |
| 263 | + /** |
| 264 | + * @ngdoc function |
| 265 | + * @name yourApp.posts.$hasArchived |
| 266 | + * @description |
| 267 | + * Operates on a collection of posts and determines whether any of them are archived |
| 268 | + * |
| 269 | + * @requires _ Lodash library is used to search the collection |
| 270 | + * |
| 271 | + * @return string Either the logo for this post, or a default logo |
| 272 | + */ |
| 273 | + $hasArchived: function() { |
| 274 | + return !angular.isUndefined(_.find(this, { archived: true })); |
| 275 | + } |
| 276 | + } |
| 277 | + }); |
| 278 | +}); |
| 279 | +``` |
| 280 | + |
| 281 | +Example: |
| 282 | + |
| 283 | +```javascript |
| 284 | +model('Posts').all().then(function(posts) { |
| 285 | + if (posts.$hasArchived()) { |
| 286 | + // Some of the posts in the collection are archived |
| 287 | + } |
| 288 | +}); |
| 289 | +``` |
| 290 | + |
| 291 | +Running unit tests |
| 292 | +-- |
| 293 | + |
| 294 | +Install the test runner with npm: |
| 295 | + |
| 296 | +```bash |
| 297 | +npm install |
| 298 | +``` |
| 299 | + |
| 300 | +You can then run the tests with gulp: |
| 301 | + |
| 302 | +```bash |
| 303 | +gulp |
| 304 | +``` |
| 305 | + |
| 306 | +Tests can be found in the `spec` directory of this project. |
| 307 | + |
| 308 | +Related |
| 309 | +-- |
| 310 | + |
| 311 | +You may wish to use [Angular Scaffold](https://github.com/radify/angular-scaffold/), which is is a collection of convenience wrappers around angular-model collections. Really helpful for building your AngularJS application with angular-model. |
0 commit comments