Angular之响应式表单 ( Reactive Forms )

项目结构

1152615-20180425172104199-112040786.png

一 首页 ( index.html )

doctype html>
<html lang="en">
<head><meta charset="utf-8"><title>Angular4ReactiveFormtitle><base href="/"><meta name="viewport" content="width=device-width, initial-scale=1"><link rel="icon" type="image/x-icon" href="favicon.ico">
head>
<body><app-hero-list>app-hero-list>
body>
html>

 

二 根模块 ( app.module.ts )

import { BrowserModule } from '@angular/platform-browser';
import { ReactiveFormsModule } from '@angular/forms';
import { NgModule } from '@angular/core';import { HeroListComponent } from './hero-list/hero-list.component';
import { HeroDetailComponent } from './hero-detail/hero-detail.component';
import { HeroService } from './hero.service';@NgModule({declarations: [HeroListComponent,HeroDetailComponent],imports: [BrowserModule,ReactiveFormsModule],providers: [HeroService],bootstrap: [HeroListComponent]
})
export class AppModule { }

 

三 列表脚本 ( hero-list.component.ts )

import { Component, OnInit } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { finalize } from 'rxjs/operators';
import { Hero } from '../model/model';
import { HeroService } from '../hero.service';@Component({selector: 'app-hero-list',templateUrl: './hero-list.component.html',styleUrls: ['./hero-list.component.css']
})
export class HeroListComponent implements OnInit {isLoading = false;heroes: Observable;selectedHero: Hero;constructor(public heroService: HeroService) { }ngOnInit() {}/*** 获取Hero列表* * @memberof HeroListComponent*/getHeroes() {this.isLoading = true;this.heroes = this.heroService.getHeroes().pipe(finalize(() => this.isLoading = false));this.selectedHero = null;}/*** 选择Hero* * @param {Hero} hero * @memberof HeroListComponent*/select(hero: Hero) {this.selectedHero = hero;}}

 

四 列表模版 ( hero-list.component.html )

<h3 *ngIf="isLoading"><i>Loading heroes ... i>
h3>
<h3 *ngIf="!isLoading"><i>Select a heroi>
h3>
<nav><button (click)="getHeroes();" class="btn btn-primary">Refreshbutton><a *ngFor="let hero of heroes | async" (click)="select(hero);">{{hero.name}}a>
nav>
<div *ngIf="selectedHero"><hr/><h2>Hero Detailh2><h3>Editing:{{selectedHero.name}}h3><app-hero-detail [hero]="selectedHero">app-hero-detail>
div>

五 详情脚本 ( hero-detail.component.ts )

import { Component, OnInit, Input, OnChanges, OnDestroy } from '@angular/core';
import { Hero, Address } from '../model/model';
import { FormBuilder, FormGroup, FormArray, AbstractControl, FormControl } from '@angular/forms';
import { HeroService } from '../hero.service';
import { provinces } from '../model/model';@Component({selector: 'app-hero-detail',templateUrl: './hero-detail.component.html',styleUrls: ['./hero-detail.component.css']
})
export class HeroDetailComponent implements OnInit, OnChanges, OnDestroy {@Input() hero: Hero;heroForm: FormGroup;provinces: string[] = provinces;nameChangeLog: string[] = [];constructor(private fb: FormBuilder, private heroService: HeroService) {this.createForm();this.logNameChanges();}/*** * getter方法:从而可以直接访问secretLairs* @readonly* @type {FormArray}* @memberof HeroDetailComponent*/get secretLairs(): FormArray {return this.heroForm.get('secretLairs');}ngOnInit() { // 单击Hero按钮,选择Hero时执行console.log('详情页面初始化');}ngOnDestroy(): void { // 单击Refresh按钮,重新获取Hero列表时执行console.log('详情页面销毁');}ngOnChanges() {this.rebuildForm();}createForm() {this.heroForm = this.fb.group({name: '',secretLairs: this.fb.array([]),power: '',sidekick: ''});}/**** 选择英雄、还原表单时重置表单* @memberof HeroDetailComponent*/rebuildForm() {this.heroForm.reset({ // 将字段标记为pristine、untouchedname: this.hero.name});this.setAddress(this.hero.addresses);}/**** 设置表单的地址* @param {Address[]} addresses* @memberof HeroDetailComponent*/setAddress(addresses: Address[]) {const addressFormGroups = addresses.map(address => this.fb.group(address));const addressForArray = this.fb.array(addressFormGroups);this.heroForm.setControl('secretLairs', addressForArray);}/*** 新增一个地址* * @memberof HeroDetailComponent*/addLair() {this.secretLairs.push(this.fb.group(new Address()));}/*** 保存表单* * @memberof HeroDetailComponent*/save() {this.hero = this.prepareCopyHero();this.heroService.updateHero(this.hero).subscribe((val) => { // 成功
},(err) => { // 出错
});this.rebuildForm();}/*** 深度复制Hero对象* * @returns {Hero} * @memberof HeroDetailComponent*/prepareCopyHero(): Hero {const formModel: any = this.heroForm.value; // AbstractControl是FormGroup、FormArray、FormControl的基类const secrectLairDeepCopy: Address[] = formModel.secretLairs.map((address: Address) => Object.assign({}, address));const savedHero: Hero = {id: this.hero.id,name: formModel.name,addresses: secrectLairDeepCopy};return savedHero;}/*** 还原表单* * @memberof HeroDetailComponent*/revert() {this.rebuildForm();}/*** 订阅valueChanges属性( Observale对象 ),监控详情页面名称的变化,选择英雄、输入名称时执行* * @memberof HeroDetailComponent*/logNameChanges() {const nameControl: FormControl = this.heroForm.get('name');nameControl.valueChanges.forEach((val: string) => this.nameChangeLog.push(val));}
}

 

六 详情模版 ( hero-detail.component.html )

<form [formGroup]='heroForm'><div style="margin-bottom: 1em;"><button type="button" (click)="save();" [disabled]="heroForm.pristine" class="btn btn-success">Savebutton><button type="button" (click)="revert();" [disabled]="heroForm.pristine" class="btn btn-success">Revertbutton>div><div class="form-group"><label class="center-block">Name:<input class="form-control" formControlName="name" />label>div><div formArrayName="secretLairs" class="well well-lg"><div *ngFor="let address of secretLairs.controls;let i = index;" [formGroupName]="i"><h4>Address #{{i+1}}h4><div style="margin-left: 1em;"><div class="form-group"><label class="center-block">Street:<input class="form-control" formControlName="street" />label>div><div class="form-group"><label class="center-block">City:<input class="form-control" formControlName="city" />label>div><div class="form-group"><label class="center-block">Province:<select class="form-control" formControlName="province"><option *ngFor="let province of provinces" [value]="province">{{province}}option>select>label>div><div class="form-group"><label class="center-block">Zip Code:<input class="form-control" formControlName="zip" />label>div>div>div><button (click)="addLair();" type="button">Add a Secret Lairbutton>div>
form><p>heroForm value: {{heroForm.value | json}}p><h4>Name change logh4>
<ul><li *ngFor="let name of nameChangeLog">{{name}}li>
ul>

 

七 服务脚本 ( hero.service.ts )

import { Injectable } from '@angular/core';
import { of } from 'rxjs/observable/of';
import { delay } from 'rxjs/operators';
import { Hero, heroes } from './model/model';
import { Observable } from 'rxjs/Observable';@Injectable()
export class HeroService {delayMs = 500;constructor() { }/*** 获取Hero对象列表* * @returns {Observable} * @memberof HeroService*/getHeroes(): Observable {return of(heroes).pipe(delay(this.delayMs));}/*** 更新Hero对象* * @param {Hero} hero * @returns {Observable} * @memberof HeroService*/updateHero(hero: Hero): Observable {const oldHero = heroes.find(h => h.id === hero.id);const newHero = Object.assign(oldHero, hero); // 潜复制return of(newHero).pipe(delay(this.delayMs));}
}

 

八 数据模型 ( model.ts )

export class Hero {constructor(public id: number, public name: string, public addresses: Address[]) {}
}export class Address {constructor(public province?: string, public city?: string, public street?: string, public zip?: number) {}
}
export const heroes: Hero[] = [new Hero(1, 'Whirlwind', [new Address('山东', '青岛', '东海路', 266000),new Address('江苏', '苏州', '干将路', 215000)]),new Hero(2, 'Bombastic', [new Address('福建', '厦门', '环岛路', 361000)]),new Hero(3, 'Magneta', [])
];export const provinces: string[] = ['山东', '江苏', '福建', '四川'];

 


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部