Angular2 / Ionic2动态表单错误:找不到具有名称的控件,无法分配给属性验证程序

时间:2017-11-27 13:18:43

标签: typescript ionic3 angular5 angular-reactive-forms reactive-forms

在我的离子项目(带有最后一个角度版本的最后一个版本)中,我使用Dynamic Forms来从我的其余api构建动态表单。

我的想法是我的后端服务器以json格式返回表单输入和我需要的所有属性(整个表单)。目的是创建动态表单,如果在我的后端编辑表单(例如添加输入或属性),我不必更新和“重新构建”我的离子应用程序以便我的更改被采取考虑到了。

所以这就是我所做的,遵循动态表单流程/教程。

首先我在ionic app.module.ts文件中声明导入import { ReactiveFormsModule } from '@angular/forms';,然后导入导入模块:

@NgModule({
  declarations: [
    MyApp,
    HomePage,
    // ...
    FormBaseComponent,
    DynamicCustomRestFormComponent,
  ],
  imports: [
    BrowserModule,
    HttpModule,
    IonicModule.forRoot(MyApp),
    ReactiveFormsModule,
    IonicStorageModule.forRoot(),
  ],
  // ...

然后我在名为/src/models/的{​​{1}}文件夹中创建了表单基本模型(相对于Question model):

form-base.ts

我在export class FormBase<T>{ value: T; key: string; label: string; required: boolean; controlType: string; name: string; fullName: string; id: number; disabled: boolean; attr: Array<any>; errors: Array<any>; constructor(options: { value?: T, key?: string, label?: string, required?: boolean, controlType?: string, name?: string, fullName?: string, id?: number, disabled?: boolean, attr?: Array<any>, errors?: Array<any>, } = {} ) { this.value = options.value; this.key = options.key || ''; this.label = options.label || ''; this.required = !!options.required; this.controlType = options.controlType || ''; this.name = options.name || ''; this.fullName = options.fullName || ''; this.id = options.id; this.disabled = !!options.disabled; this.attr = options.attr; this.errors = options.errors; } 中以例如/src/models/form-components命名的子文件夹中创建了太子*表单组件(相对于doc中的question-textbox.ts文件):

text.js

我在名为import { FormBase } from '../form-base'; export class Text extends FormBase<string> { controlType = 'text'; type: string; constructor(options: {} = {}) { super(options); this.type = options['type'] || 'text'; } } 的{​​{1}}中提供服务:

/src/providers/rest-api/ folder

作为doc上Question form components的desfribe,我通过运行命令form-service.ts(离子cli)来创建我的组件。 import { Validators, FormControl, FormGroup } from '@angular/forms'; import { HttpErrorResponse } from '@angular/common/http'; import { Injectable, Inject } from '@angular/core'; import { FormBase } from '../../models/form-base'; import { Text } from '../../models/form-components/text'; import { Http } from '@angular/http'; import { FORM_API_SUFFIX } from "../services.constants"; import { EnvVariables } from '../../app/environment-variables/environment-variables.token'; import 'rxjs/add/operator/map'; @Injectable() export class FormProvider { protected url: URL; protected suffix: string; public formInputs: FormBase<any>[] = []; constructor(public http: Http, @Inject(EnvVariables) public envVariables) { } // fetch form data by rest api fetchFormRestView(name: string = null) { let formName = name; this.suffix = FORM_API_SUFFIX + formName; this.url = new URL(this.suffix, this.envVariables.apiEndpoint); this.http.get(this.url.href) .subscribe( data => { let formData = this.getChildrenField(JSON.parse(data['_body'].toString())); return this.buildForm(this.createInputFiedlType(formData)); }, (err: HttpErrorResponse) => { if (err.error instanceof Error) { console.log('An error occurred:', err.error.message); } else { console.log(`the fetchFormFields function get a server returned code ${err.status}); } } ); } // iterate on each form field from data recovered by the rest form api getChildrenField(data) { let fieldsArray: Array<Object> = []; // loop on the keys directly Object.keys(data['children']).forEach( key => { fieldsArray[key] = data['children'][key]; }); return fieldsArray; } createInputFiedlType(data) { let fieldInfo: Array<Object> = []; // console.info("form field in array here => ", data); // The Object.keys() method returns an array of a given object's own enumerable properties, in the same order as that provided by a for...in loop (the difference being that a for-in loop enumerates properties in the prototype chain as well). Object.keys(data).forEach( key => { // console.log(key); //key fieldInfo = data[key]['vars']; // console.log(fieldInfo); //value // swith to manage and instanciate input type field for ForBase Class switch (fieldInfo['block_prefixes'][1]) { // ezpublish/symfony choice field case 'choice' : this.formInputs.push( // I have many type of field, I put only the text component but it's the same logic for all // text field default: this.formInputs.push( new Text({ key: fieldInfo['full_name'], name: fieldInfo['name'], fullName: fieldInfo['full_name'], label: fieldInfo['label'], value: fieldInfo['value'], required: fieldInfo['required'], id: fieldInfo['id'], disabled: fieldInfo['disabled'], attr: fieldInfo['attr'], errors: fieldInfo['errors'] }), ); break; } }); return this.formInputs; } // build the form buildForm(formInputs: FormBase<any>[]) { let group: any = {}; formInputs.forEach(input => { group = ({ [input.key] : input.required ? new FormControl(input.value || '', Validators.required) : new FormControl(input.value || ''), }); }); return new FormGroup(group); } } 中的一个组件。

ionic generate component

/src/components/form-base/

form-base.ts

import { Component, Input, OnInit } from '@angular/core';
import { FormGroup }                from '@angular/forms';
import { FormBase }                 from '../../models/form-base';
import { FormProvider }             from '../../providers/rest-api/form-service';

@Component({
  selector:    'form-base',
  templateUrl: 'form-base.html',
  providers:   [ FormProvider ]
})
export class FormBaseComponent implements OnInit {

  @Input() formInputs: FormBase<any>[] = [];

  form: FormGroup;

  payLoad: string = '';

  constructor(private formService: FormProvider) { }

  /**
   * @method ngOnInit
   * @return {FormGroup}
   */
  ngOnInit() {
    return this.form = this.formService.buildForm(this.formInputs);
  }


  /**
   * @method onSubmit
   * @return {[type]}
   */
  onSubmit() {
    return this.payLoad = JSON.stringify(this.form.value);
  }

}

然后我让另一个组件扩展名为form-base.html的{​​{1}}组件:

ts:

<div>
  <form (ngSubmit)="onSubmit()" [formGroup]="form">
      <div *ngFor="let input of formInputs">
        <app-form-input [input]="input" [form]="form"></app-form-input>
      </div>

    <div>
      <button ion-button type="submit" [disabled]="!form.valid">Valider</button>
    </div>
  </form>

  <div *ngIf="payLoad">
    <strong>Saved the following values</strong><br>{{payLoad}}
  </div>
</div>

html:

form-base

最后,在我的页面中,这里是我的离子视图的页面组件,我有这个:

dynamic-custom-rest-form

import { Component, Input } from '@angular/core';
import { FormGroup }        from '@angular/forms';
import { FormBase }     from '../../models/form-base';

@Component({
  selector: 'app-form-input',
  templateUrl: './dynamic-custom-rest-form.html'
})
export class DynamicCustomRestFormComponent {

  @Input() input: FormBase<any>;
  @Input() form: FormGroup;
}

<div [formGroup]="form"> <label [attr.for]="input.key">{{input.label}} :</label> <div [ngSwitch]="input.controlType"> <input *ngSwitchCase="'text'" [formControlName]="input.key" [formControl]="input.key" [id]="input.key" [type]="input.controlType" [value]="input.value" [name]="input.name" [placeholder]="input.name" /> </div> <div class="errorMessage" *ngIf="!isValid">{{input.label}} is required</div> </div>

src/pages/home/home.ts

调用表单服务时出现两个错误

首先:

  

错误:无法找到名称为:'input [inputName]'

的控件

第二个错误:

  

TypeError:无法分配给属性“validator”   “input [inputName]”:不是对象

通过遵循Angular文档,我真的不明白我的错误在哪里。

感谢。

0 个答案:

没有答案