-- 第四课:用户输入和表单

这节课我们来看Camp Details和My Details页的功能,也就是这些功能组成我们的输入功能。如果你已经完成了本书的其他应用的话,或者之前用过Ionic 2的输入域,你可能有这样用过ngModel

<ion-input type="text" [(ngModel)]="myField"></ion-input>

这种写法给输入域设置了双向数据绑定,这些我在基础部分详细讨论过,本质上他就是他这个输入域的值捆绑到本页类定义的:

this.myField

如果你改变this.myField的值的话,将会映射到这个输入框来,如果输入框的值改变的话将会被映射到this.myField。对于管理用户输入来将,这是个非常简单的方法,但是如果有更多更复杂的输入域的时候,那么就需要使用FormBuilder了。 通过使用From Builder,不仅可以使代码更漂亮,还可以在“控制”每个输入框的同时带来更多强大的功能(如果看一眼Giflists应用的话,会看到我们用来控制文本域改变的定语,通过他可以做很多神奇的事情)。 我们也可以使用Validators与Form Builder写作,他允许我们捆绑一个“验证”到指定的输入域,这个验证将会检查输入是否允许(即,是否是正确的邮件格式)。 我们直接进入实现过程吧,更直观些。我们会先实现Camp Details页面的功能,然后烤制到My Details页。 > 修改 src/pages/camp=details/camp-details.html 的列表部分为如下:

<ion-list no-lines>
    <form [formGroup]="campDetailsForm" (change)="saveForm()">

    <ion-item>
    <ion-label stacked>Gate Access Code</ion-label>
    <ion-input formControlName="gateAccessCode"   type="text"></ion-input>
    </ion-item>

    <ion-item>
    <ion-label stacked>Ammenities Code</ion-label>
    <ion-input formControlName="ammenitiesCode"   type="text"></ion-input>
    </ion-item>

    <ion-item>
    <ion-label stacked>WiFi Password</ion-label>
    <ion-input formControlName="wifiPassword" type="text"></ion-input>
    </ion-item>

    <ion-item>
    <ion-label stacked>Phone Number</ion-label>
    <ion-input formControlName="phoneNumber" type="text"></ion-input>
    </ion-item>

    <ion-item>
    <ion-label stacked>Departure Date</ion-label>
    <ion-datetime formControlName="departure"   displayFormat="DD/MM/YYYY"></ion-datetime>
    </ion-item>

    <ion-item>
    <ion-label stacked>Notes</ion-label>
    <ion-textarea formControlName="notes" type="text"></ion-textarea>
    </ion-item>
    </form>
</ion-list>

这里的输入框都差不多只是有一些比较重要的区别。首先,我们将它们包装到一个form标签中:

<form [formGroup]="campDetailsForm" (change)="saveForm()">

我们定义了formGroup的值为campDetailsForm,这个值很快就会跟Form Builder一起使用。同时,我们也监听了(change)事件并在检测到的时候触发saveForm函数,意思就是用户改变和切换输入框的时候都会触发saveForm函数,但是不会在输入单个字符的时候触发(我们想要的话也可以做到)。通常对于表单而言我们都是监听他的(submit)事件并在其中处理数据,但是我们不想用户点击“Save”按钮或者其他类似操作来处理,我们只是希望用户在输入了一个新值的时候尽快存储起来。 另一个重要的变更时我们给每个输入框添加了formControlName,并给他指定了一个名字(跟我们将要使用ngModel做的差不多)。再次,我们就快把他和Form Builder一起使用了。 现在,我们看一下类定义。首先,我们改一下构造器: > 修改 src/pages/camp-details/camp-details.ts 的构造器如下:

campDetailsForm: FormGroup;

constructor(public navCtrl: NavController, public formBuilder: FormBuilder,public dataService: Data) {
    this.campDetailsForm = formBuilder.group({
        gateAccessCode: [''],
        ammenitiesCode: [''],
        wifiPassword: [''],
        phoneNumber: [''],
        departure: [''],
        notes: ['']
    });
}

由于我们在模板中已经将formGroup定义为campDetailsForm,我们这里可以指定一个新的Form Builder组。我们通过将之前指定给输入框的formControlName提供进来创建一个新的组。注意,我们提供了一个包含了空白字符串的数组,他用于作为输入框的初始值,例如:

gateAccessCode: ['54321']

这段代码会将dateAccessCode输入框的初始值设为‘54321’。你也可以像这样在这里提供一个验证器(validator):

gateAccessCode: ['', Validators.required]

以上代码会把gateAccessCode变为必需的域。这就是设置表单的全部内容了,现在我们只要实现saveForm函数来。 > 修改 src/pages/camp-details/camp-details.ts 的 saveForm 函数:

saveForm(): void {
    let data = this.campDetailsForm.value;
    //this.dataService.setCampDetails(data);
}

注意:我们注释掉了对数据服务的调用时因为我们目前没有实现他,不然的话TypeScript会向我们抛出错误。 现在,我们可以在任何时候通过this.campDetailsForm.value获取表单的值。他将会返回一个对象包含了所有的值,也就是我们需要保存的数据。所以我们将这些数据传给数据服务去保存(现在还未实现)。 记住,saveForm函数在任何输入框改变的时候会触发,所以任何他们改变的时候我们读取这些值并保存他们。 现在我们只需要把这些变更映射到我们的My Details页。这些基本上一样的,我们我直接就复制粘贴了。不解释。 > 修改 src/pages/my-details/my-details.html 为如下:

<ion-header>
    <ion-navbar color="primary">
        <ion-title>
            <img src = "assets/images/logo.png" class="logo" />
        </ion-title>
    </ion-navbar>
</ion-header>

<ion-content padding>
    <ion-card>
        <ion-card-header>
        My Details
        </ion-card-header>
        <ion-card-content>
        Update this form with your details so you have an easy reference for
        later.
        </ion-card-content>
    </ion-card>

    <ion-list no-lines>
        <form [formGroup]="myDetailsForm" (change)="saveForm()">
        <ion-item>
        <ion-label stacked>Car Registration</ion-label>
        <ion-input formControlName="carRegistration" type="text"></ion-input>
        </ion-item>

        <ion-item>
        <ion-label stacked>Trailer Registration</ion-label>
        <ion-input formControlName="trailerRegistration" type="text"></ion-input>
        </ion-item>

        <ion-item>
        <ion-label stacked>Trailer Dimensions</ion-label>
        <ion-input formControlName="trailerDimensions" type="text"></ion-input>
        </ion-item>

        <ion-item>
        <ion-label stacked>Phone Number</ion-label>
        <ion-input formControlName="phoneNumber" type="text"></ion-input>
        </ion-item>

        <ion-item>
        <ion-label stacked>Notes</ion-label>
        <ion-textarea formControlName="notes" type="text"></ion-textarea>
        </ion-item>
        </form>
    </ion-list>
</ion-content>

> 修改 src/pages/my-details/my-details.ts的构造器如下:

myDetailsForm: FormGroup;

constructor(public navCtrl: NavController, public formBuilder: FormBuilder,public dataService: Data) {
    this.myDetailsForm = formBuilder.group({
        carRegistration: [''],
        trailerRegistration: [''],
        trailerDimensions: [''],
        phoneNumber: [''],
        notes: ['']
    });
}

> 修改 src/pages/my-details/my-details.ts的 saveForm函数如下:

saveForm(): void {
    let data = this.myDetailsForm.value;
    //this.dataService.setMyDetails(data);
}

确实,表单不是世界上最刺激的东西(最起码大部分人会这么认为),但是对于移动应用来讲他是极度重要的组件之一,所以了解他们的工作方式非常重要。学会使用Form Builder可以让你的表单更好管理更强大,但是有时候,一个简单的[(ngModel)]就足够了。 在下一节课,我们将学习稍有有趣一点的东西,也稍微复杂一点:我们来实现Google Maps!

Last updated