泰山不讓土壤,故能成其大;河海不擇細流,故能就其深。
接著介紹 Angular 的程式,這包含有許多模組。因為和 Spring Boot 侷限在 local host, 因此不用stackblitz. 如果讀者想要測試編碼,歡迎索取,在本例中產生的模組如下:
ng new angularclient --routing
ng g class user
ng g service user-service
ng g c user-form
ng g c user-list
其中 g=generate, c=component。
src/app/app.component.html
<div class="container">
<div class="row">
<div class="col-md-12">
<div class="card bg-dark my-5">
<div class="card-body">
<h2 class="card-title text-center text-white py-3">{{ title }}</h2>
<h4 class="card-title text-center text-white py-3">{{ author }}</h4>
<ul class="text-center list-inline py-3">
<li class="list-inline-item"><a routerLink="/users" class="btn btn-info">List Users</a></li>
<li class="list-inline-item"><a routerLink="/adduser" class="btn btn-info">Add User</a></li>
</ul>
</div>
</div>
<router-outlet></router-outlet>
</div>
</div>
</div>
src/app/app.component.ts
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'Angular-Spring Boot-Demo';
author = 'by Faust, 2019,9,28';
}
src/app/user-form.component.html
<div class="card my-5">
<div class="card-body">
<form (ngSubmit)="onSubmit()" #userForm="ngForm">
<div class="form-group">
<label for="name">Name</label>
<input type="text" [(ngModel)]="user.name"
class="form-control" id="name" name="name" placeholder="Enter your name"
required #name="ngModel">
</div>
<div [hidden]="!name.pristine" class="alert alert-danger">Name is required</div>
<div class="form-group">
<label for="email">Email</label>
<input type="text" [(ngModel)]="user.email"
class="form-control" id="email" name="email" placeholder="Enter your email address"
required #email="ngModel">
<div [hidden]="!email.pristine" class="alert alert-danger">Email is required</div>
</div>
<button type="submit" [disabled]="!userForm.form.valid" class="btn btn-info">Submit</button>
</form>
</div>
</div>
[(ngModel)] 是作資料庫綁定,[hidden]是特定狀況下不顯示,!name.pristine 表明只有在 name 沒有值時再顯示,[hidden]=”!email.pristine”也是相同的意思。在 [disabled]=”!userForm.form.valid” 定義在submit 時會檢視是否有效。另外,第一行也是關鍵:
<form (ngSubmit)="onSubmit()" #userForm="ngForm">
src/app/user-form.component.ts (import 的編碼都省略了)
@Component({
selector: 'app-user-form',
templateUrl: './user-form.component.html',
styleUrls: ['./user-form.component.css']
})
export class UserFormComponent {
user: User;
constructor(private route: ActivatedRoute, private router: Router, private userService: UserService) {
this.user = new User();
}
onSubmit() {
this.userService.save(this.user).subscribe(result => this.gotoUserList());
}
gotoUserList() {
this.router.navigate(['/users']);
}
}
留意到 onSubmit() 呼叫 save() (定義在 user-service.service.ts 中)。
src/app/app.module.ts
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
@NgModule({
imports: [ BrowserModule, FormsModule ],
declarations: [ AppComponent ],
bootstrap: [ AppComponent ],
schemas: [ CUSTOM_ELEMENTS_SCHEMA ]
})
export class AppModule { }
注意,因為在 app.component.html 中,有使用到標簽 <router_outlent>,這是未定義的標簽,因此會顯示錯誤,可以留意上面編碼中增加兩行,告知系統,就不會有錯誤。
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
...
schemas: [ CUSTOM_ELEMENTS_SCHEMA ]
其中 CUSTOM_ELEMENTS_SCHEMA,亦可用 NO_ERRORS_SCHEMA 取代,新增記錄全部呼叫的流程依序條列下來,我們可以順著看呼收的過程:
app-component.component.html
-> (routerLink="/users") -> app-routing.module.ts: { path: 'users' ... }
-> user-form.component.html (type=”submit”) -> user-form.comonent.ts: onSubmit()
-> this.userService.save(this.user)
-> user-service.service.ts: save(user: User)
-> this.http.post<User>(this.usersUrl, user);
==> call spring boot (back end)
另外,留意到 .subscribe( ), 這個指令還有許多變化。代表在結束(result) 執行 gotoUserList() 也就是列出所有的記錄。
src/app/model/User/User.ts
export class User {
id: string;
name: string;
email: string;
}
src/app/user-list/user-list.component.html