Getting Started
In the first post, we used Angular CLI to generate the project skeleton, and usedng 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() {
}
}
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>
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"
],
//...
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>
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>
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{}
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 { }
AppModule
.import { SharedModule } from './shared/shared.module';
//...
@NgModule({
declarations: [
AppComponent
],
imports: [
//...
SharedModule,
//...
}]
export class AppModule { }
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 { }
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 { }
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 { }
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)],
exports: [RouterModule],
providers: []
})
export class AboutRoutingModule { }
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
],
<app-navbar></app-navbar>
<div class="page">
<div class="container">
<router-outlet></router-outlet>
</div>
</div>
<app-footer></app-footer>
.page {
margin-top: 80px;
min-height: 600px;
}
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 { }
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)],
exports: [RouterModule],
providers: []
})
export class PostsRoutingModule { }
app-routing.module.ts
file, add:const routes: Routes = [
{ path: '', redirectTo: '/admin', pathMatch: 'full' }
{ path: 'posts', loadChildren: 'app/posts/posts.module#PostsModule' },
];
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',
createdAt: '9/22/16 4:15 PM'
},
{
id: 3,
title: 'Getting started with Angular2',
home: 'Home of Getting started with Angular2',
createdAt: '9/22/16 4:15 PM'
},
];
}
}
export interface Post {
id?: number;
title: string;
home: string;
createdAt?: string;
createdBy?: string;
}
import
in src\app\posts\posts.component.ts.import {Post} from './post.model';
<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>
Try to click the edit and view links in each post card. It should route to the right component view.
Component lifecycle hooks
InPostsComponent
, 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
).
评论