Skip to content
Rodrigo Vilar edited this page Feb 8, 2017 · 17 revisions

AngularM empowers Angular 2 components with objects and directives based on domain model elements, such as, entities, properties, relationships and enumerations. This way, Angular 2 components become generic and highly reusable, reducing effort to develop web front-end.

For instance, ordinary Angular 2 templates define concrete elements for every domain entity, such as the following table header:

<h1>Students:</h1>
<table>
  <tr>
    <th>Name</th>
    <th>Age</th>
    <th>Address</th>
  </tr>
</table>

Listing 1: Example of concrete Angular 2 template for a table header

In spite of being a very simple artifact, the element structure pattern of Listing 1 must be repeated for every domain entity that needs a table header.

In other hand, Angular M implements the Adaptive Object Model (AOM) architectural style, in order to decouple GUI from domain. Therefore, programmers can define generic and reusable elements, such as:

<h1>{{entityType.plural}}:</h1>
<table>
  <tr>
    <th *ngFor="let propertyType of entityType.propertyTypes">{{propertyType.name}}</th>
  </tr>
<table>

Listing 2: Example of generic Angular M template for table headers

The generic template accesses an entityType object which represents the metadata of a domain entity. In this case, it writes the entity plural name on a heading <h1>{{entityType.plural}}</h1>. This template also iterates over the entity properties *ngFor="let propertyType of entityType.propertyTypes" and writes property names on table headers <th ... >{{propertyType.name}}</th>.

To produce the HTML elements of Listing 1, the generic template of Listing 2 can be combined with following entity metadata:

entityType('Student', 'Students', {id:'name'})
  .propertyType('name', 'string')
  .propertyType('age', 'number')
  .propertyType('address', 'string')

Listing 3: Entity metadata that produces code of Listing 1

The main advantage of Listing 2 template is its reusability for any domain entity, because it can be combine with any other domain entity in order to produce table headers.

Hello world example

In order to run the simplest AngularM app, you need to:

  • Install AngularM library
  • Import AngularmModule into your AppModule
  • Define domain metadata
  • Define a generic template on a Angular 2 component
  • Combine domain metadata with a generic template in order to produce concrete HTML elements

Installing AngularM:

npm install angularm --save

Importing AngularmModule into your AppModule:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

// Import AngularM module
import { AngularmModule } from 'angularm';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AngularmModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Listing 4: hello-world - app.module.ts

Defining domain metadata:

import { entityType, memoryDAO, AngularmService } from 'angularm';

export let describeDomain = (angularm: AngularmService) => {
  angularm.setupDomain(
    memoryDAO(entityType('student', 'students', { id: 'code' } )
        .propertyType('code', 'number')
        .propertyType('name', 'string')),
    memoryDAO(entityType('client', 'clients', { id: 'id' } )
        .propertyType('id', 'number')
        .propertyType('name', 'string'))
    );
};

Listing 5: hello-world - entities.ts

Defining a generic template on a Angular 2 component:

<ul>
  <li *ngFor="let entityType of entityTypes">{{entityType.singular}}</li>
</ul>

Listing 6: hello-world - app.component.html

Combining domain metadata with a generic template in order to produce concrete HTML elements:

import { Component } from '@angular/core';
import { AngularmService, EntityTypesComponent } from 'angularm';
import { describeDomain } from './entities';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent extends EntityTypesComponent {
  constructor(angularm: AngularmService) {
    super();
    describeDomain(angularm);
    this.entityTypes = angularm.listEntityTypes();
  }
}

Listing 7: hello-world - app.component.ts

To combine metadata and generic templates, in this Hello world example, AppComponent injects the AngularM facade object AngularmService to load domain metadata describeDomain(angularm). This component also sets the this.entityTypes field that will be consumed by its template (Listing 6).

To run this example, clone AngularM-examples repository, enter hello-world directory and execute npm install and ng serve commands.

Listing table example

Another interesting example on AngularM-examples repository is simple_table, that uses other types of metadata to implement a generic listing table.

This example contains an app-listing-table Component, which loads all instances of an entityType and stores them into a entities field:

this.angularm.listAll(this.entityType.singular).then( entities => {
  this.entities = entities;
});

Listing 8: simple_table - app-listing-table.component.ts

In app-listing-table template, there a two loops. The first one creates table headers, iterating on propertyTypes of a entityType. The second loop is double, because it iterates on every entity (instance) of entities field and, for each entity, iterates on its respective property (values).

<table>
  <tr>
    <th *ngFor="let propertyType of entityType.propertyTypes">{{propertyType.name}}</th>
  </tr>
  <tr *ngFor="let entity of entities">
    <td *ngFor="let property of entity.mountProperties()">{{property.value}}</td>
  </tr>
</table>

Listing 9: simple_table - app-listing-table.component.html

To understand metadata concepts, such as entities, properties and types, please read section Metadata concepts.

Metadata concepts

AOM architectural style relies on Type Square pattern which names metadata elements as below:

  • Object classes, e.g. Student, as EntityTypes;
  • Object instances, e.g. John and Mary, as Entities;
  • Object attributes, e.g. Name and Age, as PropertyTypes;
  • Object attribute values, e.g. 'John' and 15 years, as Properties;

These four Type Square classes collaborate as Figure 1 diagram shows.

AOM Type Square pattern

Figure 1: Type square classes

AngularM implements Type Square pattern and exposes EntityTypes, Entities, PropertyTypes and Properties in its API. For this reason, programmers can setup metadata structure on application bootstrap and can use metadata elements to develop component templates.

class EntityType {
  propertyTypes: PropertyType[] = [];
  constructor(public singular: string, public plural: string, public tags: any) {...}
  pt(name: string, type: string, tags?: any): EntityType {...}
  propertyType(name: string, type: string, tags?: any): EntityType {...}
}

class PropertyType {
  constructor(public entityType: EntityType, public name: string, public type: string, public tags?: any) {}
}

class Entity {
  constructor(public entityType: EntityType, public properties: any) {}
  get key(): any {...}
  mountProperties(): Property[] {...}
}

class Property {
  constructor(public entity: Entity, public propertyType: PropertyType, public value: any) {}
}

Listing 10: AngularM Type Square API

Clone this wiki locally