Angular model objects with JavaScript classes

Source: Internet
Author: User

Angular model objects with JavaScript classesThe missing piece in AngularJS


Unlike Backbone and Ember, AngularJS does not provide a standardized-to-define model objects. The model part of mvc*-Angular is the scope object, which are not, and we mean by model objects. A model object is the JavaScript version of a class instance. Developers familiar with object oriented programming would feel right at home using model objects. I ' m a big fan of the mix of OO and functional programming that JAVASCRIPT provides.

* Actually I think of AngularJS as a viewmodel-view-controller framework, since $scope is better described as a Vie Wmodel rather than a data Model.

classes is blueprints for instantiating objects, which has a constructor and can has public, private and static proper Ties as well as public, private and static methods. There are various ways in which you can define a class in JavaScript. I prefer using a named function, with methods added to the prototype. The main reason for the naming, which gives your option to use the  instanceof  operator to Ch Eck its type. Using The prototype has the advantage of sharing functions between objects of the same class, saving memory.

whatever style of class definition you prefer, hooking them up to AngularJS are pretty straightforward. I prefer to use the  factory  function, but can use the  service  or  Provider  functions instead if you like. Here's a complete model definition:

. Factory (' User ', function  (organisation)  {   /**   *  Constructor, with class name   */  function user (firstName,  Lastname, role, organisation)  {    // Public properties,  assigned to the instance  (' this ')     this.firstName =  firstname;    this.lastname = lastname;    this.role =  role;    this.organisation = organisation;  }   / **   * public method, assigned to prototype   */   User.prototype.getFullName = function  ()  {    return  this.firstname +  '   '  + this.lastName;  };   /**    * private property   */  var possibleroles = [' admin ',  ' editor ',  ' guest ';    /**   * private function   */  function  checkrole (role)  {    return possibleroles.indexof (role)  !== -1;   }   /**   * static property   * using  copy to prevent modifications to private property   */   user.possibleroles = angular.copy (possibleroles);   /**    * static method, assigned to class   * instance  (' this ')  is not available in static context   */  user.build  = function  (data)  {    if  (!checkrole (data.role))  {       retuRn;    }    return new user (       data.first_name,      data.last_name,       Data.role,      organisation.build (data.organisation)  // another  model    );   };   /**   * return the  constructor function   */  return user;})

while the code and the comments explain a lot, there's a few things to note here. Firstly, the name of the constructor (class name) is technically unrelated to the name of the Angular factory. You could give the factory and the constructor different names, but that'll probably leads to a lot of confusion, so I re Commend keeping these in sync. In fact, minification would result in the class name to being changed to something short, while the factory name, being a str ING, remains the same. If you don't choose to diverge here, remember, the factory name are what you instantiate and need for the instanceof check , while the class name is-what if you see when you log a instance to the console.

Secondly, wrapping classes in Angular factories would provide you and the option to use dependency injection. The model object itself can be injected elsewhere in your application, and you can inject other stuff into the factory. In the example I ' ve injected organisation, which are another class like this one. I strongly recommend tonever inject anything but other models or filtersIn your models, otherwise you'll end up with circular dependencies and all hell breaks loose. If you had a need to include services in your models, you ' re doing it wrong. You can often avoid it by moving logic from the service into the model or a filter, or your model was trying to do too much Already and logic should is moved into a service.

Using Models with Services

the most common place to create model objects are in services. I often find myself writing services for a very models in my application. This is because models usually reflect a data resource (in RESTful terms), so it makes sense to has a service which acts On the API endpoint for this resource. For example, a basic organisationservice:

.factory (' Organisationservice ', function  (api, organisation)  {   return {    get: function  ()  {       return api        .get ('/organisations ')          .then (Organisation.apiresponsetransformer);       });     }  }); 

the API Service is just a wrapper for $http and returns a promise with the data of the response instead of the entire res Ponse (including headers and such). The most interesting to note are the static method Organisation.apiresponsetransformer,  which is passed a s the callback function to then (). The goal is to has all of the organisations returned by the API to being mapped to the organisation model. This allows-verify the response data and enhance it with additional properties and methods. An apiresponsetransformer could look like this:

organisation.apiresponsetransformer = function  (responseData)  {   if  (Angular.isarray (responsedata))  {    return responsedata       .map (organisation.build)       .filter ( Boolean);   }  return organisation.build (responsedata);}; 

This code would is located in the class definition of organisation. A nice thing about promises was that you can chain multiple calls to then () so can use several response Transformers T o Handle complex response data (when dealing with a not-so-restful API for example). The result is still a promise, so it's easy-to-use in your route resolve functions.

Extending classes

an important concept in object oriented programming is inheritance. Unlike true OO languages such as Java, JavaScript does not has class inheritance but Uses prototypal inheritance. The main difference is this in JavaScript, you  manually  clone the prototype object from one instance to Another (or link them by reference), instead of  declaring  inheritance on the class definition. There ' s a few options you can explore:

/** * one-way reference from subclass to superclass  (instance)  *  most of the time this is what you want. it should  be done * before adding other methods to subclass. */ Subclass.prototype = new superclass (); /** * two-way reference *  superclass will also get any subclass methods added later. */ subclass.prototype = superclass.prototype; /** * cloning behavior *  This does not setup a reference, so instanceof will not work .  */angular.extend (Subclass.prototype, superclass.prototype);  /** * enhancing a  single instance * This could be used to implement the  decorator pattern. */angular.extend (Subclassinstance, superclass.prototype); 

I ' m not going to go into the details of implementing inheritance between model objects. There ' s plenty of resources available online explaining the specifics. One reason is that I think this should was done sparingly, when it's really the single best solution. Prototypal inheritance is a powerful thing, but it's misunderstood by many. Chances is that using inheritance would only complicate things for your and your fellow developers, especially when they ar En ' t all JavaScript gurus. Most of the time it's better to accept a little code duplication between models or move the logic into a filter or service . Also, should prefer composition over inheritance.


Angular model objects with JavaScript classes

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.