Travel through Angular (Tutorial
Make a project
$ npm install -g @angular/cli
$ ng new helloworldapp
$ alias ng='/c/Users/KreivenWang/AppData/Roaming/npm/ng' //If ng command is not working. Besides, you can also configure system environments
$ cd helloworldapp
$ npm i
$ npm start
in package.json
, scripts looks like:
"scripts": {
"ng": "ng",
"start": "ng serve --open",
"build": "ng build --prod",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
},
The
--open
flag opens a browser to http://localhost:4200/.
Make a component
$ ng generate component paper
Pipe
Pipes are a good way to format strings, currency amounts, dates and other display data. Angular ships with several built-in pipes and you can create your own.
<span class="status"> - {{item.status | uppercase}}</span>
Two-way binding
<label>name:
<input [(ngModel)]="item.name" placeholder="name">
</label>
Event binding
<li (click)="onSelect(item)" > </li>
eventhandler:
onSelect(item: ToDoItem): void {
this.selectedItem = item;
}
Directives
ngIf
<p *ngIf="selectedItem">{{selectedItem.id}}</p>
ngFor
<ul>
<li *ngFor="let item of todoitems" (click)="onSelect(item)" class="wrapper">
<span class="id ver-center">[{{item.id}}]</span>
<label class="content ver-center">
<input type="text" [(ngModel)]="item.content" placeholder="What do you want to do now?">
</label>
<span class="status ver-center"> - {{item.status | uppercase}}</span>
</li>
</ul>
Style the selectedItem
in todoitems.component.css
:
.wrapper {
border-left: solid 5px tomato;
background-color: #f7e8d9;
height: 80px;
margin: 5px;
vertical-align: center;
position: relative;
}
.wrapper-selected{
border-left: solid 15px tomato;
background-color: #f7cda4;
}
<li *ngFor="let item of todoitems" (click)="onSelect(item)"
class="wrapper" [class.wrapper-selected]="item === selectedItem">
</li>
@Input Decorator
in todoitem-detail.component.ts
:
import { Component, OnInit, Input } from '@angular/core';
//in class:
@Input() todoitem: ToDoItem;
in todoitems.component.html
:
<app-todoitem-detail [todoitem]="selectedItem"></app-todoitem-detail>
ToDoItemsComponent.selectedItem => ToDoItemDetailComponent.todoitem
(It's a one way data binding from theselectedItem
property of theToDoItemsComponent
to thetodoitem
property of the target element, which maps to thetodoitem
property of theToDoItemDetailComponent
.)
Service
ng generate service paper
paper.service.ts
:
import { Injectable } from '@angular/core';
import { Paper } from '../models/paper';
import { MessageService } from './message.service';
import { Observable, of } from 'rxjs';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { catchError, map, tap } from 'rxjs/operators';
@Injectable()
export class PaperService {
private papersUrl = 'api/papers';
constructor(
private http: HttpClient,
private messageService: MessageService) { }
getPapers(): Observable<Paper[]> {
//return of([MockPaper]);
return this.http.get<Paper[]>(this.papersUrl)
.pipe(
tap(papers => this.log('fetched papers'))
);
}
private log(message: string) {
this.messageService.add('PaperService: ' + message);
}
}
message.service.ts
:
import { Injectable } from '@angular/core';
@Injectable()
export class MessageService {
public messages: string[] = [];
add(message: string) {
this.messages.push(message);
}
clear() {
this.messages = [];
}
}
QA
[TS] How can I export/import an Enum?
status.ts
:
export enum Status{On = 1, Off = 0, HalfOn, HalfOff}
and in required.ts
file import like the way given below:
import {Status} from './status';
Can't bind to 'ngModel' since it isn't a known property of 'input'
Although ngModel is a valid Angular directive, it isn't available by default.
It belongs to the optional FormsModule and you must opt-in to using it.
In the app.module.ts
, I just added :
import { FormsModule } from '@angular/forms';
[...]
@NgModule({
imports: [
[...]
FormsModule
],
[...]
})
[TS] What does class multiple constructors looks like?
import { ToDoStatus } from './todostatus';
export class ToDoItem {
id: number;
content: string;
status: ToDoStatus;
details: string[];
constructor();
constructor(id: number, content: string);
constructor(id?: number, content?: string) {
this.id = id;
this.content = content;
this.status = ToDoStatus.Pending;
this.details = ['What\'s the detail for' + content + '?', 'Anything should tell?'];
}
}
Notice of angular-in-memory-web-api
:
Notice the import for app.module.ts
, otherwise data won't be shown:
import { HttpClientModule } from '@angular/common/http';
import { HttpClientInMemoryWebApiModule } from 'angular-in-memory-web-api';
@NgModule({
imports: [
[...]
HttpClientModule,
HttpClientInMemoryWebApiModule.forRoot(InMemoryDataService, { dataEncapsulation: false })
],
[...]
})
createDb() function returns an object. So at 'return' line, don't forget to wrap 'papers' with {}
. in-memory-data.service.ts
:
createDb() {
const papers = [...];
return { papers };
}
Plus
CSS Transition
animation-duration: 1s; /* the duration of the animation */
animation-timing-function: ease-out; /* how the animation will behave */
animation-delay: 0s; /* how long to delay the animation from starting */
animation-iteration-count: 1; /* how many times the animation will play */
animation-name: slideInFromLeft; /* the name of the animation we defined above */
Begin after page loaded
The key is animation-delay
parameter set to 0s
@keyframes slideInFromTop {
0% {
transform: translateY(-100%);
}
100% {
transform: translateY(0);
}
}
.brand {
/* This section calls the slideInFromTop animation we defined above */
animation: 1s ease-out 0s 1 slideInFromTop;
}