Angular 4-用动态表单域实现多页表单

时间:2018-09-23 16:34:45

标签: angular bootstrap-4

我试图在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>

我唯一的要求是允许用户动态添加表单字段,例如多个电子邮件地址。我要寻找的是表单中有一个+和-按钮,该按钮允许用户添加多个电子邮件地址。我能够找到相同的多个解决方案,但是无法在上述代码中复制相同的解决方案。

请指导我如何实现相同目标。

谢谢!

0 个答案:

没有答案