Getting Started
In the first post,we used Angular CLI to generate the project skeleton,and used ng serve
to run this application on Angular CLI built-in webpack dev server.
Now we wil add more components,Angular CLI provides ng generate
to create a component quickly. Follow the steps that we have done in Getting started with Angular 1.5 and ES6,we will create a simple blog application.
You can get source codes from Github.
Generate posts component
Enter the project root folder,and generate a new component via:
ng g component posts
You will see the following info.
create src\app\posts\posts.component.css create src\app\posts\posts.component.html create src\app\posts\posts.component.spec.ts create src\app\posts\posts.component.ts
By default,it will create a new folder under src\app folder,named posts. And the newly created component will be generated into the posts folder.
Have a look at the home of posts.component.ts file.
import { Component,OnInit } from '@angular/core'; @Component({ selector: 'app-posts',templateUrl: './posts.component.html',styleUrls: ['./posts.component.css'] }) export class PostsComponent implements OnInit { constructor() { } ngOnInit() { } }
It declares a component named PostsComponent
.
posts.component.css is the component specific CSS style file used for PostsComponent
,posts.component.html is the template file for PostsComponent
.
posts.component.spec.ts is the unit test file.
import { TestBed,async } from '@angular/core/testing'; import { PostsComponent } from './posts.component'; describe('Component: Posts',() => { it('should create an instance',() => { let component = new PostsComponent(); expect(component).toBeTruthy(); }); });
Common page layout
Generally,a page layout could be consist of header,sidebar,home body,and footer section,and only home section are replaced with different home in different views.
In this sample,we will create a simple navbar as header and footer components to demonstrate common page layout.
Modify the AppComponent
template file app.component.html,which act as the template layout for all chidren components.
<app-navbar> </app-navbar> <h1> {{title}} </h1> <app-footer> </app-footer>
I will try to use the same layout in my Angular 1.5 and ES6 sample.
In the project root folder,install bootstrap and Ng2Bootstrap(the Angular 2 compatible component and directives).
npm install ng2-bootstrap bootstrap@next --save
You should includes the bootstrap css file. Angular CLI leaves some room to extend. Add the bootstrap css path in angular-cli.json.
//... "styles": [ "styles.css","../node_modules/bootstrap/dist/css/bootstrap.min.css" ],//...
Follow official Angular 2 style guild,generate navbar and footer components in app/shared folder.
Enter app/shared folder,execute the following command.
ng g component navbar --flat
--flat tells ng
command do not create a new folder for the created component.
It generates 4 files for navbar component,similar witht the former posts component.
Replace the template home of navbar.component.html file.
<nav class="navbar navbar-fixed-top navbar-light bg-faded"> <div class="container"> <a class="navbar-brand" [routerLink]="['/admin']" ><i class="fa fa-admin"></i>ANGULAR2 SAMPLE</a> <button class="navbar-toggler hidden-sm-up" type="button" data-toggle="collapse" data-target="#exCollapsingNavbar" aria-controls="exCollapsingNavbar2" aria-expanded="false" aria-label="Toggle navigation"> ☰ </button> <!-- Collect the nav links,forms,and other home for toggling --> <div class="collapse navbar-toggleable-xs" id="exCollapsingNavbar"> <ul class="nav navbar-nav"> <li class="nav-item" [routerLinkActive]="['active']"><a class="nav-link" [routerLink]="['/posts']" >{{'posts'}}</a></li> <li class="nav-item" [routerLinkActive]="['active']"><a class="nav-link" [routerLink]="['/posts','new']" >{{'new-post'}}</a></li> <li class="nav-item" [routerLinkActive]="['active']"><a class="nav-link" [routerLink]="['/about']" >{{'about'}}</a></li> </ul> <!-- /.navbar-collapse --> </div> </div> <!-- /.container-fluid --> </nav>
In this navbar template,it uses Bootstrap navbar component,and adds some links to different views. We will cover this links in Route section.
Similarly,generates footer component via:
ng g component footer --flat
Fill the following home in footer.component.html file.
<footer class="bg-faded" style="background-color: #e3f2fd;"> <div class="container"> <div class="row"> <div class="col-md-6 "> </div> <div class="col-md-6">Copyright: HantsyLabs</div> </div> </div> <!-- /.container-fluid --> </footer>
Since Angular 2.0 RC,a new router module is introduced for reorganizing the application logic structure. To use them,we have to import them in AppModule
and declares them in declarations
property of NgModule
annotation.
import {NavbarComponent} from './shared/navbar.component'; import {FooterComponent} from './shared/footer.component'; @NgModule({ declarations:[NavbarComponent,FooterComponent] }) export class AppModule{}
A more flexible approach is creating a SharedModule
for these component fragments,directives,pipes,etc.
mport { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { RouterModule } from '@angular/router'; import { NavbarComponent } from './navbar.component'; import { FooterComponent } from './footer.component'; @NgModule({ imports: [ CommonModule,RouterModule ],declarations: [ NavbarComponent,FooterComponent ],exports: [ NavbarComponent,FooterComponent ],}) export class SharedModule { }
And import this module in AppModule
.
import { SharedModule } from './shared/shared.module'; //... @NgModule({ declarations: [ AppComponent ],imports: [ //... SharedModule,//... }] export class AppModule { }
When this application is reloaded,you will see the app component is decorated with navbar and footer.
Route
To navigate between pages,you have to define routing rules to make all page oriented components work.
Generates some samples components/modules for demonstration.
In the project root folder,generates a admin and an about modules.
ng g component admin ng g module admin --routing
It will generate admin component files,and two an extra file: admin.module.ts and admin-routing.module.ts.
Declares AdminComponent
in admin.module.ts.
import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { AdminRoutingModule } from './admin-routing.module'; import { AdminComponent } from './admin.component'; @NgModule({ imports: [ CommonModule,AdminRoutingModule ],declarations: [AdminComponent] }) export class AdminModule { }
In admin.module.ts
file,it imports another module file,admin-routing.module.ts.
import { NgModule } from '@angular/core'; import { Routes,RouterModule } from '@angular/router'; import { AdminComponent } from './admin.component'; const routes: Routes = [ { path: 'admin',component: AdminComponent } ]; @NgModule({ imports: [RouterModule.forChild(routes)],exports: [RouterModule],providers: [] }) export class AdminRoutingModule { }
The routes defines the routing rules for this module,and we also wrap this definition in to a standard Angular 2 NgModule
.
Create another sample module,named about
.
ng g component about ng g module about --routing
The home of about.module.ts:
import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { AboutRoutingModule } from './about-routing.module'; import { AboutComponent } from './about.component'; @NgModule({ imports: [ CommonModule,AboutRoutingModule ],declarations: [AboutComponent] }) export class AboutModule { }
The home of about-routing.module.ts:
import { NgModule } from '@angular/core'; import { Routes,RouterModule } from '@angular/router'; import { AboutComponent } from './about.component'; const routes: Routes = [ { path: 'about',component: AboutComponent } ]; @NgModule({ imports: [RouterModule.forChild(routes)],providers: [] }) export class AboutRoutingModule { }
We have added admin and about link in navbar. Two directives are used: routerLink
and routerLinkActive
. routerLink
will process the target route and routerLinkActive
will toggle css class when the link is active or not.
Import these modules into app.module.ts.
import { AdminModule } from './admin/admin.module'; import { AboutModule} from './about/about.module'; @NgModule({ //... imports: [ //... AdminModule,AboutModule ],
Do not forget add route-outlet directive into app.component.html file.
<app-navbar></app-navbar> <div class="page"> <div class="container"> <router-outlet></router-outlet> </div> </div> <app-footer></app-footer>
Add css to adjust the default layout,add the following into styles.css.
.page { margin-top: 80px; min-height: 600px; }
Now run this application again,you could navigate between admin and about via links in navbar.
Loading module lazily
By default,as above settings,all modules will be loadded when application is started.
The new router supports loading modules lazily as possible.
Generates more componets in posts folder,such as new-post,post-details,edit-post.
ng g component new-post --flat ng g component edit-post --flat ng g component post-details --flat
Add these modules into posts.module.ts.
import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import {FormsModule} from '@angular/forms'; import { PostsRoutingModule } from './posts-routing.module'; import { PostsComponent } from './posts.component'; import { NewPostComponent } from './new-post.component'; import { EditPostComponent } from './edit-post.component'; import { PostDetailsComponent } from './post-details.component'; @NgModule({ imports: [ CommonModule,FormsModule,PostsRoutingModule ],declarations: [ PostsComponent,NewPostComponent,EditPostComponent,PostDetailsComponent ] }) export class PostsModule { }
And defines routing rules in posts-routing.module.ts.
import { NgModule } from '@angular/core'; import { Routes,RouterModule } from '@angular/router'; import { PostsComponent } from './posts.component'; import { NewPostComponent } from './new-post.component'; import { EditPostComponent } from './edit-post.component'; import { PostDetailsComponent } from './post-details.component'; const routes: Routes = [ { path: '',redirectTo: 'admin' },{ path: 'admin',component: PostsComponent },{ path: 'new',component: NewPostComponent },{ path: 'edit/:id',component: EditPostComponent },{ path: 'view/:id',component: PostDetailsComponent },]; @NgModule({ imports: [RouterModule.forChild(routes)],providers: [] }) export class PostsRoutingModule { }
In app-routing.module.ts
file,add:
const routes: Routes = [ { path: '',redirectTo: '/admin',pathMatch: 'full' } { path: 'posts',loadChildren: 'app/posts/posts.module#PostsModule' },];
The first routing defines an empty path property,it means this is the default path of this application. It will redirectTo /admin(the path of AdminComponent).
The second routing rule uses the lazy way to load PostsModule when navigates /posts prefix urls. At runtime,it will append /posts as prefix to all urls defined in the posts-routing.module.ts file.
You can add another routing to process the notfound path,use ** as path value,put this definition at the last postion of the routes array.
{ path: '**',component:PageNotFoundComponent}
Now try to navigate posts and new-post links in navbar,and notice the network tracking in your Chrome developer tools.
Display post list
Open src\app\posts\posts.components.ts file,add posts data in ngOnInit method.
export class PostsComponent implements OnInit { posts: Post[]; constructor() { } ngOnInit() { this.posts = [ { id: 1,title: 'Getting started with REST',home: 'Home of Getting started with REST',createdAt: '9/22/16 4:15 PM' },{ id: 2,title: 'Getting started with AngularJS 1.x',home: 'Home of Getting started with AngularJS 1.x',{ id: 3,title: 'Getting started with Angular2',home: 'Home of Getting started with Angular2',]; } }
Creat a new file src\app\posts\post.model.ts,it is a model class wrap the Post fields.
export interface Post { id?: number; title: string; home: string; createdAt?: string; createdBy?: string; }
Add import
in src\app\posts\posts.component.ts.
import {Post} from './post.model';
Open src\app\posts\posts.components.html.
<div class="card"> <div class="card-block bg-faded"> <div class="row"> <div class="col-md-9"> <form class="form-inline" (ngSubmit)="search()"> <div class="form-group"> <input type="text" name="q" class="form-control" [(ngModel)]="q" /> </div> <button type="submit" class="btn btn-outline-info">{{'search'}}</button> </form> </div> <div class="col-md-3"> <span class="pull-md-right"> <a class="btn btn-success" [routerLink]="['/posts','new']">new-post</a> </span> </div> </div> </div> </div> <div class="row"> <div class="col-md-6" *ngFor="let post of posts "> <div class="card card-block"> <h4 class="card-title">{{post.title}}</h4> <h6 class="card-subtitle text-muted">{{post.createdAt|date:'short'}}</h6> <p class="card-text">{{post.home}}</p> <div class="text-md-right"> <a [routerLink]="['/posts','edit',post.id]">edit</a> <a [routerLink]="['/posts','view',post.id]">view</a> </div> </div> </div> </div>
Save all files,when application is reloaded,navigate to http://localhost:4200/posts,you should see the following screen.
Try to click the edit and view links in each post card. It should route to the right component view.
Component lifecycle hooks
In PostsComponent
,there is a ngOnInit
method which is from OnInit
interface and it will be invoked when the component is initialized.
Inversely,when the component is being destroyed,there is a hook named OnDestroy
which has a method ngOnDestroy
which will be called.
Besides these generic lifecycle hooks,there are some other specific hooks available in Angular 2 for component lifecycle. Please read the official lifecycle hooks.
Summary
In this post,we created some components,and create a common layout for the chidren components. Also experienced the new Angular Router and used it to navigate between master view(PostsComponent
) and details view(PostDetailsComponent
).