-
Notifications
You must be signed in to change notification settings - Fork 1
Home
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.
In order to run the simplest AngularM app, you need to:
- Install AngularM library
- Import
AngularmModuleinto yourAppModule - 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.
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.
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.
JohnandMary, as Entities; - Object attributes, e.g.
NameandAge, as PropertyTypes; - Object attribute values, e.g.
'John'and15 years, as Properties;
These four Type Square classes collaborate as Figure 1 diagram shows.
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
