Lazy loading of modules in Angular 2

In the last post I shortly mentioned the ability of Angular 2 router to load lazily the application modules.

This topic deserves more explanations, so let’s go into details about this feature.

The start point is an Angular 2 applications with a couple of indipendent modules; in orther to have better performances we want to load these module lazily.

Let’s go to the implementation details.

Modules

In the application we have the usual modules Customer and Invoice; the first one:


import { NgModule } from "@angular/core";
import { Routes, RouterModule } from "@angular/router";
import { HttpModule } from "@angular/http";
import { CustomerComponent } from "./customer.component";
......

@NgModule ({
imports: [
HttpModule,
RouterModule.forChild([
{
path: "customers",
component: CustomerComponent
}])
],
exports: [
RouterModule
],
declarations: [
CustomerComponent
]
})

export class CustomerModule {}

And the second one:

import { NgModule } from "@angular/core";
import { Routes, RouterModule } from "@angular/router";
import { HttpModule } from "@angular/http";
import { InvoiceComponent } from "./invoice.component";
......

@NgModule ({
imports: [
HttpModule,
RouterModule.forChild([
{
path: "invoices",
component: InvoiceComponent
}])
],
exports: [
RouterModule
],
declarations: [
InvoiceComponent
]
})

export class InvoiceModule {}

We have defined the roots for the features modules, that must be configured forChild, according with the Angular 2 specifications.

To enable them in the application, we have to import them in the main module:

import { NgModule } from "@angular/core";
import { HttpModule } from "@angular/http";
import { RouterModule } from "@angular/router";
import { CustomerModule } from "./customer/customer.module";
import { InvoiceModule } from "./invoice/invoice.module";
......

@NgModule ({
imports: [
HttpModule,
CustomerModule,
InvoiceModule,
RouterModule.forRoot([
{
path: "",
redirectTo: "customers",
pathMatch: "full"
}
])],
exports: [
RouterModule
],
......
})

export class AppModule {}

We have finished the configuration and the if we start the application, it’ll work as expected; but we can do more.

At the moment, all the modules of the application will be loaded at the startup of the application; this is not a news, we are not surprized about that, the old angular applications worked in this way.

But with angular 2 we can do more, we are able to load the modules lazily, when required by the application.

The only thing to do is to change the configuration of the router.

Router configuration

The main change concerns the AppModule, where we have to change the configuration of the router:

import { NgModule } from "@angular/core";
import { HttpModule } from "@angular/http";
import { RouterModule } from "@angular/router";
......

@NgModule ({
imports: [
HttpModule,
RouterModule.forRoot([
{
path: "",
redirectTo: "customers",
pathMatch: "full"
},
{
path: "customers",
loadChildren: "app/customer/customer.module#CustomerModule"
},
{
path: "invoices",
loadChildren: "app/invoice/invoice.module#InvoiceModule"
},
])],
exports: [
RouterModule
]
......
})

export class AppModule {}

Instead of import the feature modules, we have defined the path of them as “Childrens”.

What we need to do now is update the paths in the customer and invoice modules:

@NgModule ({
imports: [
......
RouterModule.forChild([
{
path: "",
component: CustomerComponent
}])
],
......
})
@NgModule ({
 imports: [ 
 ......
 RouterModule.forChild([
 {
 path: "",
 component: InvoiceComponent
 }])
 ],
 ......
})

In short, we have changed the default path of the modules, because we declared these in the AppModule above.

The configuration is pretty simple but we can obtain a huge performance improvement.

Consider that in big applications, the modules wont be loaded eagerly and as a result the startup of the application will be very fast.

Here the full Angular2 project.

 

Lazy loading of modules in Angular 2

Feature modules in Angular 2

Angular 2 give us the chance to organize our application in modules.

Briefly, a module is a library where there may be components, directives and pipes and define a block of functionalities; Angular 2 libraries itself are modules, like FormsModule, HttpModule.

One cool behaviour of the modules is the ability to be loaded eagerly or lazyly through the router; this is a huge improvement, because we are able to load a module only when required and not at the startup of the application; we’ll see that the router help us in this phase.

What we’ll do in this example is define two commons modules, shared in the application; then we’ll define the feature modules, that are modules with a specific purphose; finally we’ll import them in the root module of the application.

Shared modules

In every application we have some stuff that we want to share, libraries such as translations, bootstrap, rxjs, and angular modules like FormsModule and even CommonsModule.

For these, the better choice is define a shared module that import these libraries:


import { NgModule, ModuleWithProviders, Optional, SkipSelf } from "@angular/core";
import { FormsModule } from "@angular/forms";
import { CommonModule } from "@angular/common";
import { TranslateModule } from "ng2-translate";
import { ModalModule, DatepickerModule } from 'ng2-bootstrap/ng2-bootstrap';

import "rxjs/add/observable/throw";
import "rxjs/add/observable/forkJoin";
import "rxjs/add/operator/catch";
import "rxjs/add/operator/debounceTime";
import "rxjs/add/operator/distinctUntilChanged";
import "rxjs/add/operator/map";
import "rxjs/add/operator/switchMap";
import "rxjs/add/operator/toPromise";

@NgModule ({
imports: [
FormsModule,
CommonModule,
ModalModule.forRoot(),
DatepickerModule.forRoot(),

],
exports: [
FormsModule,
CommonModule,
TranslateModule,
ModalModule,
DatepickerModule
]
})

export class SharedModule {}

What we done is import the bunch of modules that we want to include, then we defined the list of imported/exported modules.

If importing the modules is obvious, we can’t says the same thing about the export; we need to export the modules in order to make them shared; otherwise the others modules couldn’t access to these libraries.

Another behaviour that deserves a mention is the forRoot static method of the ModalModule and the DatepickerModule.

Angular 2 has a convention, so when a module has singleton services needs to implement a static method forRoot; otherwise we could provide these services, but thus the other modules could import these shared module and instantiate them.

The second module that we implement is the CoreModule, that contains the singleton services of the application:


import { NgModule, ModuleWithProviders, Optional, SkipSelf } from "@angular/core";
import { ToastModule } from "ng2-toastr/ng2-toastr";
import { SearchService } from "./search.service";
import { AlertService } from "./alert.service";

let options: any = {
autoDismiss: true,
positionClass: 'toast-bottom-right',
};

@NgModule ({
imports: [
ToastModule.forRoot(options)
]
})

export class CoreModule {
constructor (@Optional() @SkipSelf() parentModule: CoreModule) {
if (parentModule) {
throw new Error('CoreModule is already loaded. Import it in the AppModule only');
}
}

static forRoot(): ModuleWithProviders {
return {
ngModule: CoreModule,
providers: [
SearchService,
ToastModule,
AlertService
]
};
}
}

First of all, we import the ToastModule as singleton, by calling the forRoot method and passing the configuration as a parameter.

As explained above, because this module provide singleton services, have to implement a static forRoot method.

The constructor of the module class deserves an additional comment; this module must be loaded only from the root module, so to disallow the import from a feature module, we check this and eventually we throw an exception.

Feature modules

We can now implement our feature modules, that have everyone a specific purphose in the application.

For example, a CustomerModule will look like this:


import { NgModule } from "@angular/core";
import { Routes, RouterModule } from "@angular/router";
import { HttpModule } from "@angular/http";

import { SharedModule } from "../shared/shared.module";
import { CityModule } from "../city/city.module";
import { CustomerComponent } from "./customer.component";
import { CustomerDetailComponent } from "./customer.detail.component";
import { SearchCustomersPipe } from "./searchCustomers.pipe";
import { CustomerService } from "./customer.service";

@NgModule ({
imports: [
HttpModule,
SharedModule,
CityModule,
RouterModule.forChild([
{
path: "",
component: CustomerComponent
}])
],
exports: [
RouterModule
],
declarations: [
CustomerComponent,
CustomerDetailComponent,
SearchCustomersPipe
],
providers: [
CustomerService
]
})

export class CustomerModule {}

You can notice that the module import the shared module defined above.

The module deals to import the modules that needs and define with the static method forChild the root paths for the module.

Then declare the components and provide the services that belongs to the module.

App module

The last module is the root module, that is the startup module.

This module imports the shared modules of the application and define the feature modules:


import { NgModule } from "@angular/core";
import { HttpModule } from "@angular/http";
import { RouterModule } from "@angular/router";
import { BrowserModule } from "@angular/platform-browser";
import { TranslateModule } from "ng2-translate";

import { SharedModule } from "./shared/shared.module";
import { CoreModule } from "./core/core.module";
import { AppComponent } from "../app/app.component";
import { HeaderComponent } from "./header.component";

@NgModule ({
imports: [
BrowserModule,
HttpModule,
TranslateModule.forRoot(),
CoreModule.forRoot(),
SharedModule,
RouterModule.forRoot([
{
path: "",
redirectTo: "customers",
pathMatch: "full"
},
{
path: "customers",
loadChildren: "app/customer/customer.module#CustomerModule"
},
{
path: "invoices",
loadChildren: "app/invoice/invoice.module#InvoiceModule"
},
])],
exports: [
RouterModule
],
declarations: [
AppComponent,
HeaderComponent
],
bootstrap: [
AppComponent
]
})

export class AppModule {}

As you can see, the CoreModule is imported with the forRoot method, which means that is singleton as well as the RouterModule.

We defined the root paths of the router by loading the concerning modules as childrens; thus they will be loaded lazy.

So, these modules and the dependent modules will be loaded the first time only once the routing path will be fired; this is a awesome feature of Angular 2.

Here the full Angular2 project.

 

Feature modules in Angular 2

Pipes in Angular 2

Developing an Angular 1 application, filters were very useful to accomplish different needs such as filter values from an array, apply a display format to a value and so on.

In Angular 2 filters are non longer availables and the pipes take place.

Instead of filters, angular pipes are more flexible because they are able to accepts parameters as input and returning an output, and can be chained.

In this example we use a pipe to filter an array of objects.

Pipe component

We create a new pipe that will be able to filter a list of customers; in orther to do that, we need to import some stuff:


import { Pipe, PipeTransform } from "@angular/core";
import { Customer } from "./customer.model";

Now we define the Pipe component attributes:


@Pipe({
name: "searchCustomers",
pure: false
})

We defined the pipe selector and a pure attribute to false.

This because we have two types of pipes, pure and impure; a pure pipe is more efficient and fast but is able to detect changes only for primitive values (string, numbers..) or a changed object reference.

Instead, impure pipes can detect any component change; in our case we’ll have an array of customers as input, so we need an impure pipe.

Because the nature of impure pipes, you need to use these components with great care; if you notice a degrade of the performance of the application, it’s possibile to substitute the pipe with a custom component that will do the same work.

This is the code of the pipe:


export class SearchCustomersPipe implements PipeTransform {
transform(customers: Customer[], searchText: string): Customer[] {
let filteredCustomers: Customer[] = new Array<Customer>();

if (customers != undefined) {
filteredCustomers = customers.filter(c => (c.Name.indexOf(searchText) != -1) || (c.Address.indexOf(searchText) != -1));
}

return filteredCustomers;
}
}

The pipe implement the PipeTransform interface and the transform method, that accept two parameter, an array of customers and the text to search as well.

Obviously the method returns the filtered array.

The last step is register the pipe in the application module:


.....

import { SearchCustomersPipe } from "./searchCustomers.pipe";

.....

@NgModule ({

.....
declarations: [
SearchCustomersPipe
]

.....
})

Now the pipe is available to be used in the view.

Customer component

In the view we should have a list of the customers, and we want to filter that typing in a search text field.

The view will look like this:

<table class="table table-striped">
<thead>
<tr>
<th>
{{ "NAME" | translate }}</th>
<th>
{{ "ADDRESS" | translate }}</th>
<th>
{{ "CITY" | translate }}</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let customer of (customers | searchCustomers: searchText)">
<td>
{{customer.Name}}</td>
<td>
{{customer.Address}}</td>
<td>
{{customer.City.Name}}</td>
</tr>
</tbody>
</table>

We apply the searchCustomers pipe to a customers array (first parameter accepted by the pipe) and after the colon we pass the second parameter searchText.

Here the full Angular2 project.

Pipes in Angular 2

ViewChilds in Angular2

In some cases we enable the communication between a parent and a child component by using parameters passed to the child; or the parent component can waiting an event that will be emitted from the child.

But in other cases the parent need to access to methods of the child component, so we need to use another Angular2 feature, called ViewChild.

In this example we use the ViewChild to show a child component in a modal window from a parent; what we want to do is to show details about the city (city name, zip code, district) from a customer form.

Child component

We need to implement a city component, that has three fields, the name, the zip code and the district.

Starting from the import libraries we have:


import { Component, Input, Output, EventEmitter, OnInit } from "@angular/core";
import { Constants } from "../shared/commons";
import { City } from "./city.model";
import { District } from "./district.model";
import { CityService } from "./city.service";
import { DistrictService } from "./district.service";

........

There’s no news, we have two service for loading cities and districts.

Next, we define the component attributes:


@Component({
 moduleId: module.id,
 selector: "city-detail",
 templateUrl: "city.detail.component.html"
})

The class is look like this:


export class CityDetailComponent {
 @Input() city: City;
 @Output() onSaved = new EventEmitter<City>();
 @Output() onClosed = new EventEmitter();
 public districts: District[];
 public district: District;

constructor(private cityService: CityService, private districtService: DistrictService, private alertService: AlertService) { }

ngOnInit() {
 this.LoadDistricts();
 }

public Save() {
 if (this.district != null) {
 this.districtService.Post(this.district).subscribe(
 (data: District) => {
 this.city.IdDistrict = data.Id;
 this.SaveCity();
 },
 (error) => this.alertService.Error(error));
 }
 else {
 this.SaveCity();
 }

 }

public Close() {
 this.onClosed.emit();
 }

public AddDistrict() {
 this.district = {
 Id: Constants.guidEmpty,
 Name: "",
 Country: ""
 };
 }

private LoadDistricts() {
 this.districtService.GetAll().subscribe(
 (data: District[]) => {
 this.districts = data;
 }
 )
 }

private SaveCity() {
 this.cityService.Post(this.city).subscribe(
 (data) => {
 this.district = null;
 this.onSaved.emit(data);
 },
 (error) => this.alertService.Error(error));
 }
}

Also here no particular news; the component expect an input parameter of type city (the object that needs to be edit) and emit two events, when the detail is saved or when is closed.

Obviously, the parent component will be listen on these events.

We can now implement the view:

<div class="modal-dialog modal-lg">
<div class="modal-content">
<form #cityForm="ngForm" *ngIf="city">
<div class="modal-header">
<h4 class="modal-title">{{ "CITY" | translate }}</h4>
</div>
<div class="modal-body">
<div class="form-group">
<label for="name">{{ "NAME" | translate }}</label>
<input type="text" name="name" class="form-control" placeholder="{{ 'NAME' | translate }}" [(ngModel)]="city.Name" required
/>
</div>
<div class="form-group">
<label for="address">{{ "ZIP" | translate }}</label>
<input type="number" name="zip" class="form-control" placeholder="{{ 'ZIP' | translate }}" [(ngModel)]="city.Zip" required
/>
</div>
<div class="form-group">
<label for="address">{{ "DISTRICT" | translate }}</label>
<div class="row">
<div class="col-md-4" *ngIf="!district">
<select name="district" class="form-control" [(ngModel)]="city.IdDistrict" required>
<option *ngFor="let d of districts" [ngValue]="d.Id">{{d.Name}}</option>
</select>
</div>
<div class="col-md-1" *ngIf="!district">
<button type="button" class="btn btn-default" (click)="AddDistrict()">{{ 'NEW' | translate }}</button>
</div>
<div class="col-md-4" *ngIf="district">
<div class="form-group">
<label for="name">{{ "NAME" | translate }}</label>
<input type="text" name="name" class="form-control" placeholder="{{ 'NAME' | translate }}" [(ngModel)]="district.Name" required
/>
</div>
<div class="form-group">
<label for="country">{{ "COUNTRY" | translate }}</label>
<input type="text" name="country" class="form-control" placeholder="{{ 'COUNTRY' | translate }}" [(ngModel)]="district.Country"
required />
</div>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary" (click)="Save(cityForm)" [disabled]="!cityForm.form.valid">{{ "SAVE" | translate }}</button>
<button type="submit" class="btn btn-default" (click)="Close()">{{ "CLOSE" | translate }}</button>
</div>
</form>
</div>
</div>

The user can select the district from a dropdown list, or insert a new district, specifing a name and the country.

The child component is completed, now we need to render that from the parent component in a modal window.

Parent component

First of all, we’ll using ng2-bootstrap for showing the modal window.

So, in the parent component we need to import some stuff, the ViewChild decorator and the ModalDirective from the ng2-boostrap library.


import { Component, Input, Output, EventEmitter, ViewChild } from "@angular/core";

import { ModalDirective } from 'ng2-bootstrap/ng2-bootstrap';

In the component class we declare the modal component like this:

export class CustomerDetailComponent {
......
@ViewChild('citiesModal') public citiesModal: ModalDirective;
......
}

The ViewChild decorator needs child component as a paramenter, that can be the component class or a local variable; the view child is of type ModalDirective because we want to show the city detail in a modal window.

Furthermore, we add three methods to the class, the first one is for add  new city, the others are for listen the child events.

export class CustomerDetailComponent {
......
public AddCity() {
 this.city = {
 Id: Constants.guidEmpty,
 IdDistrict: "",
 Name: ""
 };

 this.citiesModal.show();
 }

 onCitySaved(city: City) {
 this.customer.IdCity = city.Id;
 this.city = city;
 this.cities.push(city);
 this.citiesModal.hide();
 }

 onCityClosed() {
 this.city = null;
 this.citiesModal.hide();
 }
......
}

The modal directive has two methods, show and hide, obviously if a new city needs to be added, the modal will be showed, otherwise (save and close events) the modal will be hidden.

The final step is the parent html page, where we add the local variable:

......
<div class="form-group">
<label for="address">{{ "CITY" | translate }}</label>
<div class="row">
<div class="col-md-3">
<select name="city" class="form-control" [(ngModel)]="customer.IdCity" [required]="validationEnabled">
<option *ngFor="let c of cities" [ngValue]="c.Id">{{c.Name}}</option>
</select>
</div>
<div class="col-md-1">
<button type="button" class="btn btn-default" (click)="AddCity()">{{ 'NEW' | translate }}</button>
</div>
</div>
<div bsModal #citiesModal="bs-modal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" aria-hidden="true">
<city-detail [city]="city" (onSaved)="onCitySaved($event)" (onClosed)="onCityClosed($event)"></city-detail>
</div>
</div>
......

The div modal has a bsModal tag that is ng2-boostrap directive and #citiesModal is the local variable specified in the ViewChild declaration above.

In the modal div we have the city detail selector with the respective properties assigned.

Here the full Angular2 project.

ViewChilds in Angular2

Master-detail component in Angular 2

One of the new features of Angular 2 is the communication between components and how they can share informations and events.

It’s very frequent that you have to implement a master/detail view, where you have a list of elements and we need to show the detail when the user click on a row.

Let’s go to implement a parent/child component, such as a customer list and a customer detail.

Customer module

In this module we have a list of the customers, and we need to have CRUD operations.

So, first of all we create the customer.component.ts file and we import the necessary modules:

import { Component, OnInit } from "@angular/core";
import { Customer } from "./customer.model";
import { City } from "./city.model";
import { Constants } from "../shared/commons";
import { CustomerService } from "./customer.service";
.......

We could have other modules used in the component, but it’s not relevant for this topic.

Now we define the component attributes:

@Component({
moduleId: module.id,
selector: "customer",
templateUrl: "customer.component.html"
})

And we start to implement the component class:

export class CustomerComponent implements OnInit {
public customers: Customer[];
public cities: City[];
public customer: Customer;
public edit = false;
public newCustomer = false;

constructor(private customerService: CustomerService, private cityService: CityService, ……) {}

ngOnInit() {
this.Load();
}

public Load() {

this.customerService.GetAll().subscribe(
(data) => {
this.customers = data;
this.customer = null;
this.translateService.get("CUSTOMERSLOADED").subscribe((res: string) => {
this.alertService.Success(res);
});
},
(error) => this.alertService.Error(error));
}
......

}

We inject the dependencies in the constructor and we load the customer list in the OnInit event of the component.

We need two methods for creating/editing of a customer as well:

public New() {
let newCustomer: Customer = {
Id: Constants.guidEmpty,
IdCity: "",
Name: "",
Address: "",
City: null
};

this.customer = newCustomer;
this.edit = true;
}

public Edit(customer: Customer) {
this.customer = customer;
this.newCustomer = false;
this.edit = true;
}

The customer property contains the object and the edit property is used to detect if the customer is in edit mode or not.

We can now implement the view:

<div [hidden]="edit">
<input type="button" class="btn btn-primary" value="New" (click)="New()" />
<table class="table table-striped">
<thead>
<tr>
<th>
{{ "NAME" | translate }}</th>
<th>
{{ "ADDRESS" | translate }}</th>
<th>
{{ "CITY" | translate }}</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let customer of customers" (click)="Edit(customer)">
<td>
{{customer.Name}}</td>
<td>
{{customer.Address}}</td>
<td>
{{cities | cityName: customer.IdCity}}</td>
</tr>
</tbody>
</table>
</div>

Customer detail component

Now we are ready to implement the detail component.

We import some libraries:

import { Component, Input, Output, EventEmitter } from "@angular/core";
import { Customer } from "./customer.model";
import { CustomerService } from "./customer.service";
import { Constants } from "../shared/commons";
.......

And we define the attributes:


@Component({
 moduleId: module.id,
 selector: "customer-detail",
 templateUrl: "customer.detail.component.html"
})

The component class has some basic methods for the CRUD operations:


export class CustomerDetailComponent {
 @Input() isNew: boolean;
 private currentCustomer: Customer;

 @Input()
 set customer(customer: Customer) {
 this.currentCustomer = customer;
 }

 get customer() {
 return this.currentCustomer;
 }

 constructor(private customerService: CustomerService, private alertService: AlertService, private translateService: TranslateService) {}

 public Save() {
 if (this.isNew) {
 this.customerService.Post(this.customer).subscribe(
 (data) => {
 this.customer = data;
 this.translateService.get("CUSTOMERSAVED").subscribe((res: string) =&amp;gt; {
 this.alertService.Success(res);
 });
 },
 (error) => this.alertService.Error(error));
 }
 else {
 this.customerService.Put(this.customer.Id, this.customer).subscribe(
 (data) => {
 this.translateService.get("CUSTOMERSAVED").subscribe((res: string) =&amp;gt; {
 this.alertService.Success(res);
 });
 },
 (error) => this.alertService.Error(error));
 }
 }

 public Close() {
 }

 public Delete() {
 this.customerService.Delete(this.customer.Id).subscribe(
 () => {
 this.translateService.get("CUSTOMERDELETED").subscribe((res: string) =&amp;gt; {
 this.alertService.Success(res);
 });
 },
 (error) => this.alertService.Error(error));
 }
 }
}

The view look like this:

<form #customerForm="ngForm">
<div class="form">
<button type="submit" class="btn btn-primary" (click)="Save(customerForm)" [disabled]="!customerForm.form.valid">{{ "SAVE" | translate }}</button>
<button type="submit" class="btn btn-danger" (click)="Delete()" *ngIf="!isNew">{{ "DELETE" | translate }}</button>
<button type="submit" class="btn btn-default" (click)="Close()">{{ "CLOSE" | translate }}</button>
<div class="form-group">
<label for="name">{{ "NAME" | translate }}</label>
<input type="text" name="name" class="form-control" placeholder="{{ 'NAME' | translate }}" [(ngModel)]="customer.Name" /></div>
<div class="form-group">
<label for="address">{{ "ADDRESS" | translate }}</label>
<input type="text" name="address" class="form-control" placeholder="{{ 'ADDRESS' | translate }}" [(ngModel)]="customer.Address" /></div>
</div>
</form>

Now we need to implement the communication between the two components.

Communication

In the customer component we add two methods that they will be executed when a customer detail will be closed or deleted:

export class CustomerComponent implements OnInit {
......
onClosed(customer: Customer) {
 this.customer = customer;
 this.edit = false;
 }

onDeleted(customer: Customer) {
 this.customers.splice(this.customers.indexOf(this.customer), 1);
 this.edit = false;
 }
}

These methods will be binded to the events that will happen in the detail component.

In the component view we add the customer detail element:

<customer-detail *ngIf="customer" [hidden]="!edit" [customer]="customer" [isNew]="newCustomer" (onClosed)="onClosed($event)" (onDeleted)="onDeleted($event)"></customer-detail>

Two of the attributes defined in the component selector are the onClosed and onDeleted; so we need to define this properties in the detail component:

export class CustomerDetailComponent {
.......
@Output() onClosed = new EventEmitter<Customer>();
@Output() onDeleted = new EventEmitter<Customer>();
.......
}

The Output keyword means that this is an output property of the component and this property is an EventEmitter with a specific type.

We can now emit this events in the related methods:

export class CustomerDetailComponent {
.......
public Close() {
 this.onClosed.emit(this.customer);
}

public Delete() {
 this.customerService.Delete(this.customer.Id).subscribe(
 () => {
 this.translateService.get("CUSTOMERDELETED").subscribe((res: string) => {
 this.alertService.Success(res);
 });
 this.onDeleted.emit(this.customer);
 },
 (error) => this.alertService.Error(error));
 }
.......
}

We defined these methods above and now we added the emission of the output events; the binded methods of the customer component will be executed.

Here the full Angular2 project.

Master-detail component in Angular 2

Mandatory fields validation with knockoutjs extenders

Knockout is a lightweight javascript library that help us to bind the UI with a model and build rich web UI interactions.

The main behaviour of this library are the observable variables, that allow us to make a bidirectional binding between the html fields and the view model of the page.

An interesting feature is extend the observable variables, enriching them with some aditional functionalities; in this example we’ll extend the observable variables with a control for the mandatory fields.

The extender

The extenders allow us to “extend” an observable variable with some behaviours; in this case, we want to add a control for the mandatory fields:


ko.extenders.required = function(target, message) {
target.hasError = ko.observable(false);
target.errorMessage = ko.observable(message || "The field is mandatory.");

function validate(value) {
target.hasError(value ? false : true);
}

validate(target());
target.subscribe(validate);

return target;
};

The function accept two parameters, the target object and the message to show and has the related properties.

The function “validate” set the correct value of hasError property, is called when the main function is loaded and it has been binded to the target object.

We’ll use this extender in our web page.

The view model

We define the view model of the page.


function ViewModel() {
var self = this;

self.FirstName = ko.observable("").extend({ required: "" });
self.LastName = ko.observable("").extend({ required: "" });

self.OnSubmit = ko.observable(false);
self.OnSendData = ko.observable(false);

self.Submit = function () {
self.OnSubmit(true);

if (!self.FirstName.hasError() && !self.LastName.hasError()) {
self.SendData();
}
}

self.Unsubmit = function () {
self.OnSubmit(false);
}

self.SendData = function () {
self.OnSendData(true);
}
}

Has you can see, we are using the extender in the properties definition; we extend the FirstName and LastName properties with the “required” extender; the syntax:

self.FirstName = ko.observable(“”).extend({ required: “” });

means that we pass to the extender two parameters, the first one is the target property (the observable) and the second one is the message (the empty string).

In the submit function we check the value of the hasError property and then we send the data.

The page

Now we are ready to implement the web page.


<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8" />

		<link rel="stylesheet" type="text/css" href="Content/main.css"/>
<script type="text/javascript" src="scripts/jquery-3.1.1.js"></script>
 <script type="text/javascript" src="scripts/knockout-3.4.0.js"></script>
<script type="text/javascript" src="scripts/extenders.js"></script>
 <script type="text/javascript" src="scripts/viewModel.js"></script>

<script type="text/javascript">
 $(function () {
 var vm = new ViewModel();
 ko.applyBindings(vm);
 });
 </script>
</head>
<body>
<script type="text/html" id="field-error">


<div>
 <input type="text" data-bind="value: field, css: { fieldError: $root.OnSubmit() && field.hasError }" />
 <span data-bind="text: field.errorMessage, visible: $root.OnSubmit() && field.hasError" class="labelError"></span>
</div>


 </script>
<div>
<label>First name</label>
<div data-bind="template: { name: 'field-error', data: { field: FirstName } }"></div>
</div>
<div>
<label>Last name</label>
<div data-bind="template: { name: 'field-error', data: { field: LastName } }"></div>
</div>
<div>
<input type="button" data-bind="click: Submit" value="submit" /></div>
<div>
<label data-bind="visible: OnSendData">Send Data!</label></div>
</body>
</html>

We have defined a template “field-error” that is composed by an input text field and by an error label.

The field has a bind to the value and to the css as well:

<input type=”text” data-bind=”value: field, css: { fieldError: $root.OnSubmit() && field.hasError }” />

The css is conditioned to the OnSubmit event and to the hasError property of the extender.

If all of these properties are true, the fieldError class need to be applied.

The error label is similar:

<span data-bind=”text: field.errorMessage, visible: $root.OnSubmit() && field.hasError” class=”labelError”></span>

The only difference is the text, binded to the errorMessage property of the extender, that we have initialized to an empty string in the view model above.

Then we use the template to define the fields:

Finally, the small css used in this example:


.labelError {
color: #ff0000;
}

.fieldError {
border-color: #ff0000;
}

 

Mandatory fields validation with knockoutjs extenders

Register and test per-request services with Autofac

When we develop web application, like ASP.NET applications, we often need to implement a service with some informations related to the user request, such as session/account infos.

In this case, the service will be tied to the web request lifecycle and there will be an instance of the service for each request.

Autofac help us to manage the instances and the life cycles of these services.

Service

We can develop a simple service that we use for our tests:


public class AccountService
{
private ITokenService _tokenService;

public AccountService(ITokenService tokenService)
{
_tokenService = tokenService;
}
}

Module

In order to register the service, we use an Autofac module:


public class PerRequestModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<AccountService>()
.AsSelf()
.InstancePerRequest()
.WithParameter(new ResolvedParameter(
(pi, ctx) => pi.ParameterType == typeof(ITokenService),
(pi, ctx) => ctx.ResolveKeyed<ITokenService>("singletonTokenService")
));
}
}

The service was defined has InstancePerRequest; we also specified explicitly the implementation of the parameter interface.

And register it in the Autofac container:


var builder = new ContainerBuilder();
...
builder.RegisterModule(new PerRequestModule());
...
containerBuilder = builder.Build();

Test methods

Now, the last step is the test methods:


[Test]
public void should_is_not_the_same_instance_for_different_requests()
{
AccountService accountService1, accountService2;

using (HttpRequestMessage request = new HttpRequestMessage())
{
request.SetConfiguration(httpConfiguration);
var dependencyScope = request.GetDependencyScope();
accountService1 = dependencyScope.GetService(typeof(AccountService)) as AccountService;
}

using (HttpRequestMessage request = new HttpRequestMessage())
{
request.SetConfiguration(httpConfiguration);
var dependencyScope = request.GetDependencyScope();
accountService2 = dependencyScope.GetService(typeof(AccountService)) as AccountService;
}

ReferenceEquals(accountService1, accountService2).ShouldBeEquivalentTo(false);
}

[Test]
public void should_be_able_to_resolve_instance_per_request()
{
using (HttpRequestMessage request = new HttpRequestMessage())
{
request.SetConfiguration(httpConfiguration);
var dependencyScope = request.GetDependencyScope();
AccountService service = dependencyScope.GetService(typeof(AccountService)) as AccountService;

service.Should().NotBeNull();
}
}

In order to be able to test a per-request service, we need an instance of the HttpRequestMessage class and set the configuration with the httpConfiguration defined in the Autofac container; then we can use the request scope to get an instance of our services and make the test.

You can find the source code here.

Register and test per-request services with Autofac