Angular2: Step by Step guide of using Angular Material 2 with Angular2 & Typescript for ASP.NET Core in Visual Studio 2015

Standard

Angular Material 2.0.0 has been released recently for Angular 2. In order to integrate Angular Material in project, follow the below steps:

Step 1: Install npm package for angular material, hammerjs, material typing

npm install --save @angular/material hammerjs
npm install --save-dev @types/angular-material @types/hammerjs

screenshot_6

Note:
The slide-toggle and slider components have a dependency on HammerJS.

Step 2: Include hammerjs to the types section of tsconfig.json file

{
  "compilerOptions": {
    "types": [
      "hammerjs"
    ]
  }
}

 

Step 3: Include @angular/material to the SystemJS configuration in case project is SystemJS for module loading

System.config({
  map: {
    ...,
    '@angular/material': 'npm:@angular/material/bundles/material.umd.js'
  }
});

Note:
Actual material 2 website state ‘npm:@angular/material/material.umd.js’ but I am getting error by systemjs, unable to find materialjs file, so simple solution is fix in url: ‘npm:@angular/material/bundles/material.umd.js’

Step 4: Include material css and hammerjs explicitly in _Layout.cshtml

 @{ var lib = "@angular"; }

<environment names="Development">
  <link href="~/node_modules/@lib/material/core/theming/prebuilt/indigo-pink.css" />
  <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
  http://~/node_modules/hammerjs/hammer.min.js
</environment>

 

Step 5: Import the Angular Material NgModule

import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { HttpModule } from '@angular/http';
import { BrowserModule } from '@angular/platform-browser';

import { MaterialModule } from '@angular/material';
import 'node_modules/hammerjs/hammer.js';

import { DashboardMainModule } from './dashboard/dashboard.module';
import { AppComponent } from './app.component';
import { AppRoutingModule  } from './app.routing';
import { APP_PROVIDERS } from './app.provider';

@NgModule({
    imports: [
        //angular builtin module
        BrowserModule,
        HttpModule,

        //ui module
        MaterialModule.forRoot(),

        //application feature module
        DashboardMainModule,
        AppRoutingModule 
    ],
    declarations: [
        AppComponent
    ],
    providers: [
        APP_PROVIDERS
    ],
    bootstrap: [
        AppComponent
    ],
    schemas: [
        CUSTOM_ELEMENTS_SCHEMA
    ]
})

export class AppModule {
}

Finally material integration is done and running.

screenshot_7

Advertisements

Angular2: Auto Populate data for component on startup using Resolve feature of Angular 2 Routing

Standard

If we were using a real world api, there may be some delay in when the data we want to display gets returned. We don’t want to display a blank component until the data loads in this situation.

We’d like to pre-fetch data from the server so it’s ready the moment our route is activated. We’d also like to handle the situation where our data fails to load or some other error condition occurs. We want to delay rendering of our route component until all necessary data has been fetched or some action has occurred.

Resolve guard is an interface we can implement as a service to resolve route data synchronously or asynchronously.

Data services usually resolve our this issue, they are easy to implement, maintain and super fun to read. Solution is simple define setter/getter for particular variable in service and then import this service in multiple components to read or write value.

First of all setup resolve property in routing configuration file.

Bold code below shows this design guideline implementation

route-config.ts:

import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';

import { SearchMovieMainComponent } from './search-movies-main.component';
import { SearchMovieComponent } from './search-movie/search-movie.component';
import { SearchMovieListComponent } from './search-movie/search-list.component';
import { GetAllMoviesResolve } from './shared/service/get-all-movies.service';

@NgModule({
    imports: [
        RouterModule.forChild([
            {
                path: 'movie',
                component: SearchMovieMainComponent,
                children: [
                    {
                        path: 'searchMovie',
                        component: SearchMovieComponent
                    },
                    {
                        path: 'searchMovieList',
                        component: SearchMovieListComponent,
                        resolve: {
                            resolvedAllMovieList: GetAllMoviesResolve
                        }
                    }
                ]
            }
        ])
    ],
    exports: [
        RouterModule
    ]
})

export class SearchMoviesRoutingModule { }

I usually use service to implement resolve functionality specially if it needs to talk to server for receiving/pushing data. We want to be explicit about the data we are resolving, so we implement the Resolve interface with a type of MovieListModel. This lets us know that what we will resolve will match our MovieListModel model. We then implement the resolve method that supports a Promise, Observable or a synchronous return value.

Bold code below shows this design guideline implementation

get-all-movies.service.ts:

import { Injectable } from '@angular/core';
import { Resolve, ActivatedRouteSnapshot } from '@angular/router';
import { Http, Response, Headers, RequestOptions } from '@angular/http';
import 'rxjs/add/operator/toPromise';
import { MovieListModel } from '../model/movie.model';

@Injectable()
export class GetAllMoviesResolve implements Resolve<MovieListModel> {
    headers: Headers;
    options: RequestOptions;

    constructor(private http: Http) {
        this.headers = new Headers({ 'Content-Type': 'application/json', 
                             'Accept': 'q=0.8;application/json;q=0.9' });
        this.options = new RequestOptions({ headers: this.headers });
    }

    resolve(route: ActivatedRouteSnapshot): Promise<MovieListModel> | boolean {            
        return this.http
            .get('api/Movie/GetAllMovies', this.options)
            .toPromise()
            .then((result: MovieListModel) => {
                return result;
            })
            .catch(error => console.log(error));
    }
}

Then I consume this resolve functionality inside my component code in ngOnIt() method.

Bold code below shows this design guideline implementation

resolve-service.ts:

import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRoute, Params } from '@angular/router';
import { MovieListModel } from '../shared/model/movie.model';


@Component({
    selector: 'search-movie-list',
    templateUrl: '../../Scripts/app/search-movies/search-movie-list.component.html'
})

export class SearchMovieListComponent implements OnInit {
    movieListModel: MovieListModel;

    constructor(
        private router: Router,
        private route: ActivatedRoute) {
    }

    ngOnInit() {
        //get data from resolve feature of routing
        this.route.data.forEach((data: { resolvedAllMovieList: MovieListModel }) => {
            this.movieListModel = data.resolvedAllMovieList;
        });
    }

}

Angular2: Error – Can’t bind to ‘ngForOf’ since it isn’t a known property

Standard

While displaying data from web-api in html code, I used *ngFor, which is a repeater directive — a way to customize data display.

2016-10-28-16_40_42-speechimdb-microsoft-visual-studio

I came across below issue: 

EXCEPTION: Unhandled Promise rejection: Template parse errors:
Can’t bind to ‘ngForOf’ since it isn’t a known property of ‘li’.
Property binding ngForOf not used by any directive on an embedded template. Make sure that the property name is spelled correctly and all directives are listed in the “directives” section

 

2016-10-28-16_37_01-home-page-my-asp-net-application

Solution:

You should import the BrowserModule in your app module and import CommonModule in children modules. You should only import BrowserModule once. Other modules should be importing CommonModules instead.

Children Module(Dashboard):

import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { CommonModule } from '@angular/common';

import { DashboardComponent } from './dashboard.component';

@NgModule({
 imports: [
     FormsModule,
     CommonModule
   ],
 declarations: [
     DashboardComponent
   ]
})

export class DashboardMainModule {
}

Main Module:

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

import { DashboardMainModule } from './dashboard/dashboard.module';
import { AppComponent } from './app.component';

@NgModule({
 imports: [
    BrowserModule,
    DashboardMainModule
  ],
 declarations: [
    AppComponent
  ],
 bootstrap: [
    AppComponent
  ]
})

export class AppModule {
}

Angular2: Lazy Loading in Angular2 Error: BrowserModule has already been loaded. If you need access to common directives

Standard

While implementing Lazy Loading in Angular 2, came across this error:

EXCEPTION: Uncaught (in promise): Error: BrowserModule has already been loaded. If you need access to common directives such as NgIf and NgFor from a lazy loaded module, import CommonModule instead.

screenshot_5

Solution:

As error description is self explanatory, the module for which you want to implement lazy loading shouldn’t import BrowserModule as this is already been imported earlier (mainly in app.component). You should only import BrowserModule once. Other modules should be importing CommonModules instead.

See code below for understanding:

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';

import { SearchMovieMainComponent } from './search-movies-main.component';

@NgModule({
    imports: [
        CommonModule
    ],
    declarations: [
        SearchMovieMainComponent
    ]
})
export class SearchMoviesMainModule {
}

 

Angular2: Lazy Loading in Angular2 Error: Cannot find ‘default’ in module

Standard

While implementing Lazy Loading in Angular 2, came across this error:

EXCEPTION: Uncaught (in promise): Error: Cannot find ‘default’ in ‘Scripts/app/search-movies/search-movies-main.module’

screenshot_5

Solution:

as stated in official documentation https://angular.io/docs/ts/latest/guide/router.html

If we look closer at the loadChildren string, we can see that it maps directly to our crisis-center.module file where we previously built out our Crisis Center feature area. After the path to the file we use a # to denote where our file path ends and to tell the Router the name of our CrisisCenter NgModule. If we look in our crisis-center.module file, we can see it matches name of our exported NgModule class.

Add the exported class name of your module to the loadChildren string after hash(#)

{
    path: '',
    loadChildren: 'app/search-movies/search-movies-main.module'
}

change to

{
    path: '',
    loadChildren: 'app/search-movies/search-movies-main.module#SearchMoviesMainModule'
}

 

 

Angular2: Import Lodash into Angular2 application using Typescript

Standard

Follow below steps to add lodash into your Angular2 app using Typescript 2.0.

Please note I am using Typescript 2.0 and Angular 2.0

Step 1:

Include lodash as the dependencies in package.json file by CMD

> npm install --save lodash

Step 2:

Include lodash typings as the dev dependencies in package.json file by CMD for Typescript otherwise you will get error in Visual Studio/Visual Code that “Cannot find module ‘lodash’

> npm install --save-dev @types/lodash

After above commands your package.json will be updated as below:

screenshot_1

Step 3:

As I am using systemJS to load module, so Update the systemjs.config.js file to map lodash. This file provides information to a module loader about where to find application modules, and registers all the necessary packages.

map: {
        'lodash': 'npm:lodash'
     },
        
packages: {
            lodash: {
                main: 'index.js',
                defaultExtension: 'js'
            }
          }

Step 4:

Import lodash in your angular component.

import * as _ from "lodash";

Please note that If you use import _ from “lodash”, you will receive following error that “Module ‘lodash’ has no default export”:

screenshot_3

Step 5:

Use lodash in your code as per need just like below as I am using _.isEqual(a,b) and IntelliSense is working fine:

screenshot_4

Update:

Lot of things have been changed since Angular2 RTM, I was having issues like “cannot find namespace ‘_’ and Cannot find name ‘many’ ”

Solution: Update @types/lodash in package.json to Typescript 2.0 compatible types in order to use lodash without any issue

"@types/lodash": "ts2.0"

Visit this link for complete solution:

Cannot find name ‘many’ and namespace ‘_’ issues with Lodash in Angular2 application using Typescript

 

Cheers. Happy Coding.