angular學習進階(十五)
阿新 • • 發佈:2020-07-13
resolve(解決守衛)
保證了資料獲取後在進行路由跳轉,防止因為資料延遲而出現的空元件情況
簡單的理解成解決延遲守衛
建立一個介面
product/product.ts
ng g i product/product.ts
export interface Product {
id: number;
name: string;
price: number
}
建立一個服務
ng g s product/product
import {Injectable} from '@angular/core'; import {Observable, of} from 'rxjs'; import {Product} from './product'; import {delay} from 'rxjs/internal/operators/delay'; import {ActivatedRouteSnapshot, Resolve, RouterStateSnapshot} from '@angular/router'; @Injectable({ providedIn: 'root' }) export class ProductService implements Resolve<Product[]> { constructor() { } // 模擬請求 getList(): Observable<Product[]> { return of([ {id: 12, name: 'sss', price: 124}, {id: 13, name: 'xxx', price: 1231}, {id: 14, name: 'bbb', price: 132}, ]).pipe(delay(2000)); } // 把請求放在延遲函式中 resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Product[]> | Promise<Product[]> | Product[] { return this.getList();// 可以對這個值進行二次加工 } }
app-routing.module
{
path: 'three',
component: ThreeComponent,
resolve: {products: ProductService}
}
從其他頁面跳轉到three頁面
<a [routerLink]="['three']">three</a>
ThreeComponent
頁面拿到這個值
export class ThreeComponent implements OnInit { constructor(private route:ActivatedRoute) { } ngOnInit(): void { // 拿到獲取的資料 console.log(this.route.snapshot.data['products']); } }
rxjs 中的map和switchMap區別
switchMap 建立一個內部課觀察物件,進行訂閱併發出其值為可觀察者
of(1, 2, 3, 4).pipe( map(v => v * 2), toArray() ).subscribe(res=>{ console.log(res); //[2, 4, 6, 8] }) of(1, 2, 3, 4, 5).pipe( switchMap(val => of(val * 2)), toArray() ).subscribe(res=>{ console.log(res); // [2, 4, 6, 8, 10] })
點選按鈕,每1s傳送一個值,再次點選,取消之前的訂閱重新開始傳送值
<button #button>click</button>
@ViewChild('button') button;
ngAfterViewInit(): void {
fromEvent(this.button.nativeElement,'click').pipe(
switchMap(()=>interval(1000))
).subscribe(res=>{
console.log(res);
})
}
比如拿到xxx/:id
this.activateRoute.paramMap.pipe(
switchMap(params=>params.get('id'))
).subscribe(res=>{
console.log(id)
})
from表單觸發某個值,提交請求
this.mainForm.get("productCode").valueChanges
.pipe(
debounceTime(700),
switchMap(val => {
return this.queryDepositData();
})
)
.subscribe(data => {
this.product=data;
})
Rxjs 學習原理圖
看著原理圖學習,會印象深刻一些
angular的相關命令細節
--flat 強制修改建立檔案的位置
ng g c --f fix/hello
在app的fix/hello位置下建立一個hello元件
-export 新增到對應模組的exports
ng g c home --export
// 會新增到對應模組的exports
--prefix 新增元件選擇器字首
ng g c --p=d hello
// 選擇器的名稱 d-hello
selector: 'd-hello',
--selector 替換元件選擇器
ng g c fix/hello-e --selector=hello-g
selector: 'hello-g',// 而不是hello-e
建立一個class 檔案
ng g class xxx
建立模組
ng g m south //會建立一個south模組
ng g m south --routing // 同時建立模組和路由
如果建立了模組沒有沒有建立路由,可以使用下面的命令
ng g m -f south --routing
模板字串規範
不好
{{num/60}}
推薦
{{num}}
get num(){
return this.total/60
}
父子元件傳遞
不好
{{getOffer(amount)}}
@Input() amount:number
getOffer(amount:number){
if(amount > 3500 && amount < 4999)
return `You will get 20% off on 5k purchase`;
else if (amount > 5000)
return `You will get 30% off on 7k purchase`;
else
return `5% off on your existing purchase.`;
}
推薦
{{offerMessage}}
offerMessage: string;
@Input() set amount(value: number) {
let message: string = '';
if (value > 5000)
message = `You will get 30% off on 7k purchase`;
else if (value > 3500 && value < 4999)
message = `You will get 20% off on 5k purchase`;
else
message = `5% off on your existing purchase.`;
this.offerMessage = message;
}
正常情況下這樣也行
{{getGrade(student)}}
getGrade(marks: number) {
let grade: string = 'F';
if (marks >= 85)
grade = 'S'
else if (marks > 60 && marks < 85)
grade = 'A'
return grade;
}
在使用ngFor 繫結資料的時候
<tr *ngFor="let student of students; trackBy:trackByFn">
<td>{{student.name}}</td>
<td>{{student.grade}}</td>
</tr>
trackByFn(index, item) {
return item.id;
}
RXjs 具體api的實際運用
debounceTime
輸入資料搜尋資料的時候,而不按搜尋的資料按鈕,請求下拉框
我們發現當修改一個的時候回立刻請求值,所以我們可以加上,在一段時間內,修改只會發一次請求
this.from.get('xxx').valueChanges.pipe(
debounceTime(300),
switchMap(key=>this.http.get('xxx',key))
)
distinctUntilChanged
噹噹前值和之前值有變化才會傳送訂閱
<form [formGroup]="myForm">
<input formControlName="firstName">
</form>
constructor(private fb: FormBuilder,) {
}
myForm = this.fb.group({
firstName: ['']
}
);
ngOnInit(): void {
this.myForm.get('firstName').valueChanges.pipe(
debounceTime(300),// 當300ms沒有新資料,才會執行
distinctUntilChanged()// 當[內容真正有修改]時,才執行搜尋
).subscribe(res=>{
console.log(res);
})
}
filter
this.myForm.get('firstName').valueChanges.pipe(
debounceTime(300),// 當300ms沒有新資料,才會執行
distinctUntilChanged(),// 當[內容真正有修改]時,才執行搜尋
filter(key =>key.length>4)// 當之大於4的是偶,才會進行搜尋
).subscribe(res => {
console.log(res);
});
Subject
public sub = new Subject();
sub.subscribe(res=>{
console.log(res); //2,3,5,6
})
this.sub.next(2);
this.sub.next(3);
this.sub.subscribe(res=>{
console.log(res); //5,6
})
this.sub.next(5)
this.sub.next(6)
ReplaySubject
// 指定記錄次數
public subject = new ReplaySubject(2);
ngOnInit(): void {
this.subject.next(1);
this.subject.subscribe(res=>{
console.log(res); //1,2,3,4
})
this.subject.next(2)
this.subject.next(3)
this.subject.subscribe(res=>{
console.log(res);//2,3,4 (2,3是最近2次重播的值)
})
this.subject.next(4)
}
asyncSubject
只有在
complete()
才會被呼叫,訂閱到[最後一次next()
]的內容
public asySub = new AsyncSubject();
ngOnInit(): void {
this.asySub.subscribe(res=>{
console.log(res); //3
})
this.asySub.next(1)
this.asySub.next(2)
this.asySub.next(3)
this.asySub.complete()
}
處理錯誤
subject.subscribe(
res=>{
// 成功
},error=>{
// 失敗
})
修改,記錄錯誤類似於try...catch
this.http.get('....').pipe(
catchError(err=>{
console.log(err)
return of([])
})
)
如果想主動丟擲錯誤
this.http.get('....').pipe(
tap(data=>{
if(data.length==0){
throwError('no data')
}
}),
catchError(err=>{
console.log(err)
return of([])
})
)
finalize
放置到最後執行的程式,這樣this.lading=false
就不用subscribe
裡面了
this.http.get('...').subscribe(res=>{
this.loading=false;
},error=>{
this.loading=false;
})
修改
this.http.get('...').pipe(
finalize(()=>{
// 不管出現什麼錯誤等等等,都一定會進入finalize裡面
this.loading=false
})
)