鹳是一个大型水鸟科的通称。包括19个品种。在大多数地球上比较温暖的地带都可以见到它们的踪迹。鹳是候鸟,善于飞行。鹳有很长的腿和细长的带蹼的爪子。它们有又长又结实的尖喙。羽毛通常是白色和黑色的。但有些品种鹳的头上或头上和脖子上几乎没有羽毛。
JavaScript Series:
- JavaScript Foundation and Node.js
- Create a backend server by Node.js (JavaScript version) or Create Server by Node.js (TypeScript version)
- Angular for frontend development
Angular is the frontend part of the MEAN stack, consisting of MongoDB database, Express.js web application server framework, Angular itself, and Node.js runtime environment.
We follow the quickstart tutorial of angular to create a application in our JavaScript blog series.
Angular Version 4.2.3
Quickstart
npm install -g @angular/cli
ng new training-javascript-angular
cd training-javascript-angular
ng serve --open
Change the title to ‘Tiven’s App’ in src/app/app.component.ts, then the server will rebuild automatically, and the page in the browser will be refreshed automatically. ng keeps the app transpiling and running.
Try to change styles in the file src/app/app.component.css and view the different on the page.
ng build
Wechat Message App
In the previous article Create a backend server by Node.js (JavaScript version) we have created a server for receiving wechat messages and storing in the database. Next we follow the tutorial Tour of Heroes of angular to create an application wechat message management application for managing the wechat messages.
Component
Show Messages List
Add the message list in the file app.component.html
<ul class="messages">
<li *ngFor="let message of messages">
{ { message.text } }
</li>
</ul>
Add the property messages in the AppComponent class.
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'Tiven App';
messages = [{
text: 'message 1'
}, {
text: 'message 2'
}];
}
Now you can see the message list in the page.
Style the messages
Add css styles in file app.component.css:
.messages li {
cursor: pointer;
position: relative;
left: 0;
background-color: #EEE;
margin: .5em;
padding: .3em 0;
height: 1.6em;
border-radius: 4px;
}
Handle click events
export class AppComponent {
...
selectedMessage: any;
onSelect(message: any): void {
this.selectedMessage = message;
}
}
onSelect(message: any): void {}
selectedMessage: any;
<ul class="messages">
<li *ngFor="let message of messages" (click)="onSelect(message)">
</li>
</ul>
<div>
<h2>selected message</h2>
<div></div>
</div>
(click)="onSelect(message)"
<div></div>
<div *ngIf="selectedMessage">
</div>
Data Model
Declare the data model type in a independent class:
message.ts:
export class Message {
id: number;
type: string;
text: string;
}
Change the data type declaration in the component class:
selectedMessage: Message;
onSelect(message: Message): void {
this.selectedMessage = message;
}
Services
Split the service logic into a service class:
message.service.ts:
import { Injectable } from '@angular/core';
import { Message } from './message';
@Injectable()
export class MessageService {
getMessages(): Message[] {
return [
{
id: 1,
type: 'subscribe',
text: 'message 1'
}, {
id: 2,
type: 'unsubscribe',
text: 'message 2'
}
];
}
}
@Injectable()
app.component.ts:
...
import { MessageService } from './message.service';
@Component({
...
providers: [MessageService]
})
export class AppComponent implements OnInit {
...
messages: Message[];
constructor(
private messageService: MessageService
) {}
ngOnInit(): void {
this.messages = this.messageService.getMessages();
}
selectedMessage: Message;
onSelect(message: Message): void {
this.selectedMessage = message;
}
}
messages: Message[];
providers: [MessageService]
constructor(private messageService: MessageService) {}
ngOnInit(): void {this.messages = this.messageService.getMessages();}
HTTP Service
import { Injectable } from '@angular/core';
import { Headers, Http } from '@angular/http';
import 'rxjs/add/operator/toPromise';
import { Message } from './message';
@Injectable()
export class MessageService {
private messagesUrl = 'http://localhost:6001/api/message';
constructor(private http: Http) { }
getMessages(): Promise<Message[]> {
return this.http.get(this.messagesUrl)
.toPromise()
.then(response => response.json() as Message[])
.catch(this.handleError);
}
private handleError(error: any): Promise<any> {
console.error('An error occurred', error); // for demo purposes only
return Promise.reject(error.message || error);
}
}
import { Headers, Http } from '@angular/http';
import 'rxjs/add/operator/toPromise';
constructor(private http: Http) { }
getMessages(): Promise<Message[]> {
this.http.get(this.messagesUrl).toPromise().then()
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpModule } from '@angular/http';
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
HttpModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
import { HttpModule } from '@angular/http';
imports: [BrowserModule, HttpModule]
app.component.ts:
ngOnInit(): void {
this.messageService.getMessages().then((messages)=> {
this.messages = messages;
});
}
Routing
Split Message Detail View into a Component
Create file message-detail.component.ts:
import 'rxjs/add/operator/switchMap';
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Params } from '@angular/router';
import { Location } from '@angular/common';
import { Message } from './message';
import { MessageService } from './message.service';
@Component({
selector: 'message-detail',
templateUrl: './message-detail.component.html',
styleUrls: [ './message-detail.component.css' ]
})
export class MessageDetailComponent implements OnInit {
message: Message;
constructor(
private messageService: MessageService,
private route: ActivatedRoute,
private location: Location
) {}
ngOnInit(): void {
this.route.params
.switchMap((params: Params) => this.messageService.getMessage(+params['id']))
.subscribe(message => this.message = message);
}
goBack(): void {
this.location.back();
}
}
Create file message-detail.component.html:
<div *ngIf="message">
<h2> details!</h2>
<div>
<label>type: </label></div>
<div>
<label>text: </label>
<input [(ngModel)]="message.text" placeholder="text" />
</div>
<button (click)="goBack()">Back</button>
</div>
Add method getMessage in class file message.service.ts
getMessage(id: number): Promise<Message> {
const url = `${this.messagesUrl}/${id}`;
return this.http.get(url)
.toPromise()
.then(response => response.json() as Message)
.catch(this.handleError);;
}
Add routes in Root Module
import { RouterModule, Routes } from '@angular/router';
...
const routes: Routes = [
{ path: 'message/:id', component: MessageDetailComponent }
];
@NgModule({
declarations: [
AppComponent,
MessageDetailComponent
],
imports: [
RouterModule.forRoot(routes),
...
],
...
})
export class AppModule { }
import { RouterModule, Routes } from '@angular/router';
const routes: Routes = [{ path: 'message/:id', component: MessageDetailComponent }];
imports: [RouterModule.forRoot(routes)
declarations: [MessageDetailComponent
Add the router outlet in
<router-outlet></router-outlet>
Serve in Express
ng build
copy the files in dist into public in node.js server project.
Comments