最新消息:XAMPP默认安装之后是很不安全的,我们只需要点击左方菜单的 "安全"选项,按照向导操作即可完成安全设置。

Angular 網站實例 – 會員報告篇

XAMPP下载 admin 639浏览 0评论
 Angular 網站實例 – 會員報告篇
今天開始 今天完成

今天的目標:完成網站實例(使用服務)

修改報告服務
為了提供元件一份報告的詳細內容,我們在報告服務增加一項 getReport(id:number) 函數如下
src/app/member/services/reports.service.ts

//… 省略
getReport(id: number): Observable<Report> {
return this.reports$.pipe(
map(reports => {
return reports.filter(report => report.id

=== id)[0];
})
);
}
這個函數很簡單的將目前的 reports,用陣列運算子 .filter()取得跟參數 id 一樣的報告,因為 .filter() 會回覆一個陣列,我們取一個回覆,這個回覆還是一個 Observable

報告元件 (report.component)
第一步:修改 src/app/member/report/report.component.ts

import { Component, OnInit } from ‘@angular/core’;
import { ActivatedRoute, ParamMap } from ‘@angular/router’;

import { ReportsService } from ‘../services/reports.service’;
import { Report } from ‘../../models’;
import { Observable } from ‘rxjs/Observable’;

@Component({
selector: ‘app-report’,
templateUrl: ‘./report.component.html’,
styleUrls: [‘./report.component.css’]
})
export class ReportComponent implements OnInit {

report$: Observable<Report>;
constructor(
private reportService: ReportsService,
private route: ActivatedRoute
) { }

ngOnInit() {
let id = this.route.snapshot.paramMap.get(‘rptId’);
this.report$ = this.reportService.getReport(+id);
}
}
加入 ReportsService, ActivatedRoute, ParamMap
ActivateRoute 可以取得目前路徑,我們在前一篇 定義 member-routing.module.ts 時,定義過 { path: ‘report/:rptId’, component: ReportComponent },這個地方我們可以用 this.route.snapshot.paramMap.get(‘rptId’) 來取得目前的 report id
利用上面增加的服務來取得報告
第二步: 修改 report.component.html

<div class=”container” *ngIf=”(report$ | async) as report”>
<header class=”center”><h3>{{report.master}}</h3></header>
<section>
<img alt=”report image” src=”{{report.image}}” class=”image”/>
</section>

<section>
<div class=”title”>{{ report.title }}</div>
<p>{{report.report}}</p>
</section>
</div>
用 async pipe 取訂閱 report$,其他用很簡單的方式來顯示報告內容

第三步:修改 report.component.css

.container {
max-width: 700px;
margin-right: auto;
margin-left: auto;

}
header {
margin: 10px auto;
text-align: center;
}
section {
margin-top: 50px;
padding-left: 20px;
padding-right: 20px;
}
.image {
display:block;
width: 100%;
height: 100%;
margin: auto;
box-sizing: border-box;
}
.title {
font-size: 20px;
font-weight: 800;
}
用 css 稍加美化,這時由前面報告摘要元件,點入一個摘要,就會導入如以下截圖

QQ截图20181011155401
 到這裡簡單的報告篇大致完工,我們回頭來更新一些連結

更新瀏覽列以及使用者登入
第一步:更新瀏覽列 (navbar) src/app/navbar/navbar.component.html

//…省略
<a mat-button *ngIf=”!(login$| async)” routerLink=”/user/login”>會員登入</a>
<a mat-button *ngIf=”login$ | async” routerLink=”/member”>會員中心</a>
<button *ngIf=”user$ | async ” mat-button [matMenuTriggerFor]=”userMenu”>
<span>{{user$ | async}}</span> <mat-icon>arrow_drop_down</mat-icon>
</button>
//… 省略
將會員中心的 routerLink 指向 /member
第二步:更新使用者登入 src/app/user/login/login.component.ts,我們在會員成功登入後,頁面導向 ‘/member’

//… 省略
import { Router } from ‘@angular/router’;
//…
constructor(
private fb: FormBuilder,
private userService: UserService,
private router: Router,
private snackbar: MatSnackBar
) { }
//…
login() {
this.userService.login(this.form.value)
.subscribe(res => {
if (res) {
this.snackbar.open(‘登入成功’, ‘OK’, { duration: 3000 });
this.router.navigate([‘/member’]);
} else {
//…
加入 Router
在登入成功後導向 /member,使用 this.router.navigate([‘/member’])
增加路由防護
在登出的狀態下,如果使用者手工打入 http://localhost:4200/member ,會出現空白頁,因為我們將後端鎖住,不讓未登入的要求取得報告,這樣對使用者經驗 (UX) 不太好,我們希望在使用者進入會員的區域時,如果是未登入,將頁面導向登入畫面,讓會員執行登入
第一步:增加一個目錄 src/app/guards

mkdir guards
第二步:用 angular-cli 增加一個 guard,順便註冊到 app.module.ts

ng generate guard auth –module app -d
第三步:修改 auth.guard.ts

import { Injectable } from ‘@angular/core’;
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, CanLoad, Router, Route } from ‘@angular/router’;
import { Observable } from ‘rxjs/Observable’;

import { UserService } from ‘../user/service/user.service’;
import { tap } from ‘rxjs/operators’;

@Injectable()
export class AuthGuard implements CanActivate, CanLoad {
loginStatus$: Observable<boolean>
constructor(
private userService: UserService,
private router: Router
) {
this.loginStatus$ = userService.getLoginStatus();
}
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
let url: string = state.url;
return this.checkLogin(url);
}
canLoad(route: Route): Observable<boolean> {
let url = `/${route.path}`;
return this.checkLogin(url);
}
checkLogin(url: string): Observable<boolean> {
return this.loginStatus$.pipe(
tap(status => {
if (!status) {
this.router.navigate([‘user/login’]);
}
}),
take(1)
);
}
}
導入 UserService 跟 Router
這個 class 要 implement CanActivate 跟 CanLoad 兩個介面,CanActivate 是給一般的 path 使用,我們要保護整個會員區域,因為它使用延遲加載 (lazy loading),所以會用到 CanLoad
建立一個變數 loginStatus$ 它會是 UserService 的目前登入狀態
建一個函數 checkLogin(),這裡用 rxjs 5.5 建議使用的 pipe() 運算子,詳情請看官方文件,再用 tap 運算子,這個運算子其實是以前的 .do 用來 “監聽” 資料,它本身不會對資料做改變,但是當我們 “監聽” 到未登入資料時,我們用 this.router.navigate([‘user/login’]) 來導向登入畫面,用運算子 take(1) 來完成資料取得
CanActivate() 跟 CanLoad() 呼叫這個函數,回應 this.loginStatus$
第四步:修改 app-routing.module.ts

//… 省略
import { AuthGuard } from ‘./guards/auth.guard’;
const routes: Routes = [{
path: ”,
children: [
{ path: ‘home’, component: HomeComponent },
{ path: ‘user’, redirectTo: ‘/user’, pathMatch: ‘full’ },
{ path: ‘member’, loadChildren: ‘./member/member.module#MemberModule’, canLoad: [AuthGuard] },
{ path: ”, redirectTo: ‘/home’, pathMatch: ‘full’ },
]
}];
//… 省略
第五步:檢查一下 app.module.ts,angular-cli 有時會在註冊 service 發生錯誤

//… 省略
import { AuthGuard } from ‘./guards/auth.guard’;

@NgModule({
//… 省略
providers: [
AuthGuard,
UtilsService,
StartupService,
{
provide: APP_INITIALIZER,
useFactory: startupServiceFactory,
deps: [StartupService, Injector],
multi: true,
},
//…省略
測試一下,在未登入狀態下,手工打入 http://localhost:4200/member 會出現以下截圖

QQ截图20181011155408

專案回顧

好了,我們網站大致完成,當然在實際的網站,我們還要加入後台管理,像是報告的 CRUD (Create, Read, Update, Delete)等等,但是基本上架構已經架好,只要在後端,會員模組加入這些功能,當然還要加上資料庫,我們就先到此為止。

回顧一下,到目前很簡單功能網站的資料流,當然這種情況下,維護系統還不是太難

我們可以想像,當專案越來越大,它有一天可能會變成,甚至更複雜

這時候,牽一髮而動全身,專案裡面的人可能沒有人有辦法指出修改某一項服務,會造成的影響,我們接下來的時間裡,要將這個網站改造,變成下面

讓元件跟服務分開,資料的流動是單方向的

我想這樣大家也會更了解為什麼要用 ngrx/store 了

 

转载请注明:XAMPP中文组官网 » Angular 網站實例 – 會員報告篇

您必须 登录 才能发表评论!