Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / HTML

Making AngularJS and mODELcLASSjs work together

5.00/5 (1 vote)
1 Jun 2015CPOL4 min read 6.7K   12  
Using mODELcLASSjs in combination with AngularJS allows you to define constraints in a declarative way supporting responsive HTML5 validation, it simplifies storage management, with the cloud storage service Parse.com for instance, and provides the option of multiple inheritance.

Introduction

By using the model-based framework mODELcLASSjs in an AngularJS Web Application we can implement the application more safer and easier. This article will introduce some basic usages of mODELcLASS working together with AngularJS. For checking every detail you can download the example application (Please use Firefox to open the index.html file or put the application source code to a localhost).

There is also an article that introduced some features of mODELcLASSjs written by Gerd Wagner.

Background

I'm developing a web application with a topic of public library using angularjs and also trying to make it works together with mODELcLASSjs. This article is based on my project.

Using AngularJS we can build a web application very fast, but we can also implement the application with help of mODELcLASSjs framework and get many benefits as following:

  • The class/model structure will be clear;
  • Constraints can be predefined during implementing a class/model;
  • Based on the predefined contraints mODELcLASS can also validate the input-value;
  • mODELcLASS can help us to manipulate the data with Parse cloud storage;
  • Subtyping is also easier to realize.

A short introduction about mODELcLASSjs

mODELcLASSjs can be used for the model layer of a MVC JavaScript web app, which may be built, for instance, with the help of a front-end framework such as AngularJS or KnockoutJS. It provides a meta-class for creating JavaScript model classes (like Book, Author and Publisher) with declarative constraint validation, storage management, and the option of multiple inheritance and object pools.

Set up a model and Define some constraints

Initializing a Book model using mODELcLASSjs is just like draw an UML class diagram with necessary constraints but in JSON-format:

<code>Book = new mODELcLASS({
  typeName: "Book",
  storageAdapter: {
    name: "Parse-REST-API",
    predefinedAttributes: ["objectId","createdAt","updatedAt"],
    applicationId: "XYZ",
    restApiKey: "XYZ"
  },
  properties: {
    "isbn": {range:"NonEmptyString", isStandardId: true, label:"ISBN", pattern:/\b\d{9}(\d|X)\b/,
      patternMessage:'The ISBN must be a 10-digit string or a 9-digit string followed by "X"!'},
    "title": {range:"NonEmptyString", min: 2, max: 50, label:"Title"},
    "year": {range:"Integer", min: 1459, max: util.nextYear(), label:"Year"},
    "edition": {range:"PositiveInteger", optional: true, label:"Edition"}
  }
});
</code>
  • typeName: defines the name of this class type (it's recommended to set the same name as the class variable).
  • storageAdapter: mODELcLASSjs provides several adapters like "LocalStorage", "Parse-REST-API" and "XHR/MySQL" for different process. We will use Parse cloud storage, which contains some predefined attributes, and need "Application ID" and "REST API KEY" to get access to the server.
  • properties: all the properties of Book will be defined here and each property has following constraints:
    • range: it's necessary to contain range in each property, which can be declared as String, NonEmptyString, Integer, NonNegativeInteger, PositiveInteger, Decimal, Date and Boolean;
    • one of these properties must be the standard identifier by defining isStandardId: true;
    • label is the name of the property;
    • pattern describes a regular expression, that the value of this property should be matched;
    • patternMessage can be used for specifying an error message according to the pattern that you've defined.
    • min/max defines the interval of numeric or string length;
    • optional can be true if the value of this property is optional (false by default);
    • unique can be true if the value of this property is unique;
    • minCard/maxCard can be defined when a multi-valued property is array-valued or map-valued. minimum/maximum cardinality of a multi-valued property (default: 1/1), maxCard may be infinity.

Working together with AngularJS we put the code into the "Run Blocks", so that the Book will be setup once the application runs.

Manipulate data with Parse.com

We've created a model Book as an instance of mODELcLASS, its storageAdapter has been also defined at the same time.

Suppose we've collected the user inputs about a book into $scope.book, with the help of mODELcLASSjs we can easily implement the basic CRUD operations:

 Operation   Request Method   Angular Click Event  mODELcLASS Function
Creat POST $scope.addBook() Book.add( $scope.book)
Read GET $scope.loadAll() Book.loadAll( { continueProcessing: function (e, obj) {...}})
Update PUT $scope.updateBook() Book.update( $scope.book)
Delete DELETE $scope.destroyBook() Book.destroy( $scope.book)

By loading all the book instances from Parse.com we are using Book.loadAll(...) with a continueProcessing(e, obj) function, which is used for asynchronous communications:

  • e is designed for getting an error message, but here its value will automatically be null.
  • obj is response object, which contains all book objects. For instance there are two book records {isbn: "0000000000", title: "book1", ...} and {isbn: "1111111111", title: "book2", ...} in database, then:
    • the form of obj is Object { 0000000000: Object, 1111111111: Object};
    • each Object within the braces is the corresponded book instance;
    • we can also converse the response obj to array using Object.keys( obj).map( function ( k) { return obj[k];}).

So for loading all book instances and combining these data with Angular front end, we assign all records to $rootScope.books:

<code>Book.loadAll( { continueProcessing: function ( e, obj) {
  $rootScope.books = Object.keys( obj).map( function ( k) { return obj[k];});
}});
</code>

Validation

We had also defined constraints for each property of class Book. If we want to validate the user inputs and get the validation's message, it's so easy, that we only need to write one code line for each property. As an example, to validate the property isbn:

<code>Book.check( "isbn", $scope.book.isbn).message;
</code>

Subtyping

Using mODELcLASSjs to implement Subtyping we can add supertype during initializing a subclass.

Suppose we define a mODELcLASS Person, and want to define a subtype Student (without constraints):

<code>// Person
Person = new mODELcLASS({
  typeName: "Person",
  ...
  properties: {
    "personId": {range:"Integer", isStandardId:true, label:"Person ID"},
    "name": {range:"String", label:"Name"}
  }
});
// Student, subtype of Person
Student = new mODELcLASS({
  typeName: "Student",
  ...
  supertype: Person,
  properties: {
    "studNo": {range:"Integer", unique:true, label:"Student no."}
  }
});
</code>

The Person's properties will naturely be inherited by Student.

One Issue

mODELcLASSjs is easy to use, but please be attention that mODELcLASSjs will only check the value of a property, of which has been assigned, otherwise mODELcLASSjs will not make validating in the background, even the property had been defined as a Standard ID. Because of this problem, we'd better predefining an empty instance of book model into $scope at the very beginning of BooksController for instance:

<code>$scope.book = {
  isbn: "",
  title: "",
  year: 0
};</code>

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)