我试图在Angular 4中实现多页表单,该表单应该能够执行以下操作:
1-允许用户浏览不同的表单页面。
2-应该能够返回到表格的上一页,并且仍然能够看到他所做的输入。
3-能够动态添加表单字段,例如多个电话号码,地址等。
通过遵循以下链接中描述的教程,我可以实现表单中的前两个功能:
https://www.cc28tech.com/angular-multi-step-wizard-part-1/
但是对于我来说,第三部分是棘手的部分。我无法理解如何继续实现这一目标。我知道我将不得不使用一个表单数组,但是在上面链接中提到的代码中实现相同的表单对我来说是棘手的。如果有人可以指导我如何实现这一目标,那将对我有很大的帮助。
以下是同一代码段:
formData.model.ts
export class FormData {
firstName: string = '';
lastName : string = '';
email: string = '';
work: string = '';
street: string = '';
city: string = '';
state: string = '';
zip: string = '';
clear() {
this.firstName = '';
this.lastName = '';
this.email = '';
this.work = '';
this.street = '';
this.city = '';
this.state = '';
this.zip = '';
}
}
export class Personal {
firstName: string = '';
lastName : string = '';
email: string = '';
}
export class Address {
street: string = '';
city: string = '';
state: string = '';
zip: string = '';
}
formData.service.ts
import { Injectable } from '@angular/core';
import { FormData, Personal, Address } from './formData.model';
import { WorkflowService } from '../workflow/workflow.service';
import { STEPS } from '../workflow/workflow.model';
@Injectable()
export class FormDataService {
private formData: FormData = new FormData();
private isPersonalFormValid: boolean = false;
private isWorkFormValid: boolean = false;
private isAddressFormValid: boolean = false;
constructor(private workflowService: WorkflowService) { }
getPersonal(): Personal {
// Return the Personal data
var personal: Personal = {
firstName: this.formData.firstName,
lastName: this.formData.lastName,
email: this.formData.email
};
return personal;
}
setPersonal(data: Personal) {
// Update the Personal data only when the Personal Form had been
validated successfully
this.isPersonalFormValid = true;
this.formData.firstName = data.firstName;
this.formData.lastName = data.lastName;
this.formData.email = data.email;
// Validate Personal Step in Workflow
this.workflowService.validateStep(STEPS.personal);
}
getWork() : string {
// Return the work type
return this.formData.work;
}
setWork(data: string) {
// Update the work type only when the Work Form had been validated
successfully
this.isWorkFormValid = true;
this.formData.work = data;
// Validate Work Step in Workflow
this.workflowService.validateStep(STEPS.work);
}
getAddress() : Address {
// Return the Address data
var address: Address = {
street: this.formData.street,
city: this.formData.city,
state: this.formData.state,
zip: this.formData.zip
};
return address;
}
setAddress(data: Address) {
// Update the Address data only when the Address Form had been validated
successfully
this.isAddressFormValid = true;
this.formData.street = data.street;
this.formData.city = data.city;
this.formData.state = data.state;
this.formData.zip = data.zip;
// Validate Address Step in Workflow
this.workflowService.validateStep(STEPS.address);
}
getFormData(): FormData {
// Return the entire Form Data
return this.formData;
}
resetFormData(): FormData {
// Reset the workflow
this.workflowService.resetSteps();
// Return the form data after all this.* members had been reset
this.formData.clear();
this.isPersonalFormValid = this.isWorkFormValid =
this.isAddressFormValid = false;
return this.formData;
}
isFormValid() {
// Return true if all forms had been validated successfully; otherwise,
return false
return this.isPersonalFormValid &&
this.isWorkFormValid &&
this.isAddressFormValid;
}
}
workflow.model.ts
export const STEPS = {
personal: 'personal',
work: 'work',
address: 'address',
result: 'result'
}
workflow-guard.service.ts
import { Injectable } from '@angular/core';
import {
CanActivate, Router,
ActivatedRouteSnapshot,
RouterStateSnapshot,
CanLoad, Route
} from '@angular/router';
import { WorkflowService } from './workflow.service';
@Injectable()
export class WorkflowGuard implements CanActivate {
constructor(private router: Router, private workflowService:
WorkflowService { }
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):
boolean {
let path: string = route.routeConfig.path;
return this.verifyWorkFlow(path);
}
verifyWorkFlow(path) : boolean {
console.log("Entered '" + path + "' path.");
// If any of the previous steps is invalid, go back to the first invalid
step
let firstPath = this.workflowService.getFirstInvalidStep(path);
if (firstPath.length > 0) {
console.log("Redirected to '" + firstPath + "' path which it is the
first invalid step.");
let url = `/${firstPath}`;
this.router.navigate([url]);
return false;
};
return true;
}
}
workflow.service.ts
import { Injectable } from '@angular/core';
import { STEPS } from './workflow.model';
@Injectable()
export class WorkflowService {
private workflow = [
{ step: STEPS.personal, valid: false },
{ step: STEPS.work, valid: false },
{ step: STEPS.address, valid: false },
{ step: STEPS.result, valid: false }
];
validateStep(step: string) {
// If the state is found, set the valid field to true
var found = false;
for (var i = 0; i < this.workflow.length && !found; i++) {
if (this.workflow[i].step === step) {
found = this.workflow[i].valid = true;
}
}
}
resetSteps() {
// Reset all the steps in the Workflow to be invalid
this.workflow.forEach(element => {
element.valid = false;
});
}
getFirstInvalidStep(step: string) : string {
// If all the previous steps are validated, return blank
// Otherwise, return the first invalid step
var found = false;
var valid = true;
var redirectToStep = '';
for (var i = 0; i < this.workflow.length && !found && valid; i++) {
let item = this.workflow[i];
if (item.step === step) {
found = true;
redirectToStep = '';
}
else {
valid = item.valid;
redirectToStep = item.step
}
}
return redirectToStep;
}
}
personal.component.ts
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { Personal } from '../data/formData.model';
import { FormDataService } from '../data/formData.service';
@Component({
selector: 'app-personal',
templateUrl: './personal.component.html'
})
export class PersonalComponent implements OnInit {
title = 'Tell us about Yourself';
personal: Personal;
form: any;
constructor(private router: Router, private formDataService:
FormDataService) {}
ngOnInit() {
this.personal = this.formDataService.getPersonal();
console.log('Personal feature loaded!');
}
save(form: any): boolean {
if (!form.valid) {
return false;
}
this.formDataService.setPersonal(this.personal);
return true;
}
goToNext(form: any) {
if (this.save(form)) {
// Navigate to the work page
this.router.navigate(['vendorOnboarding/work']);
}
}
back()
{
this.router.navigate(['/login']);
}
}
personal.component.html
<form #personalForm="ngForm" class="editForm" novalidate>
<div class="tab-pane fade in active">
<h4 class="head text-center">{{title}}</h4>
<br/>
<div class='row'>
<div class='col-xs-offset-1 col-xs-10 col-sm-offset-2 col-sm-8'>
<div class="row">
<div class='col-xs-12 col-sm-6'>
<div class="form-group">
<label class="control-label" for="firstname">First
Name</label>
<input class="form-control input-md"
#firstname="ngModel" required id="firstname"
name="firstname" type="text" placeholder="First Name"
[(ngModel)]="personal.firstName">
<div class="alert alert-danger"
[hidden]="firstname.valid">First Name is
required</div>
</div>
</div>
<div class='col-xs-12 col-sm-6'>
<div class="form-group">
<label class="control-label" for="lastname">Last
Name</label>
<input class="form-control input-md"
#lastname="ngModel" required id="lastname"
name="lastname" type="text" placeholder="Last Name"
[(ngModel)]="personal.lastName">
<div class="alert alert-danger"
[hidden]="lastname.valid">Last Name is
required</div>
</div>
</div>
</div>
<div class="form-group">
<label class="control-label" for="email">Email</label>
<input class="form-control input-md" #email="ngModel"
required pattern="^[^\s@]+@[^\s@]+\.[^\s@]{2,}$" id="email"
name="email" type="text" placeholder="Email"
[(ngModel)]="personal.email">
<div class="alert alert-danger" [hidden]="email.valid">Email
is required and must be valid</div>
</div>
<div class="form-group text-center">
<button class="btn btn-success btn-outline-rounded btn-info"
[disabled]="!personalForm.valid"
(click)="goToNext(personalForm)"> Next <span style="margin-
left:10px;" class="glyphicon glyphicon-arrow-right"></span>
</button>
</div>
</div>
</div>
</div>
</form>
我唯一的要求是允许用户动态添加表单字段,例如多个电子邮件地址。我要寻找的是表单中有一个+和-按钮,该按钮允许用户添加多个电子邮件地址。我能够找到相同的多个解决方案,但是无法在上述代码中复制相同的解决方案。
请指导我如何实现相同目标。
谢谢!