加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

angular – 如何在动态组件中使用反应形式

发布时间:2020-12-17 07:16:35 所属栏目:安全 来源:网络整理
导读:BackgroundI从包含 HTML的服务器接收客户端生成的数据,然后我使用该数据创建一个动态组件,该组件将被注入并显示在我们的客户端中.我收到的HTML可以包含一个或多个我需要通过Angular Reactive Forms绑定的输入. 尝试1:我试图通过简单地使用[innerHTML]属性并
BackgroundI从包含 HTML的服务器接收客户端生成的数据,然后我使用该数据创建一个动态组件,该组件将被注入并显示在我们的客户端中.我收到的HTML可以包含一个或多个我需要通过Angular Reactive Forms绑定的输入.

尝试1:我试图通过简单地使用[innerHTML]属性并创建动态Reactive Forms来绑定到输入来解决这个问题.但是,由于使用innerHTML属性的技术限制,该方法失败.一旦HTML在浏览器中呈现,所有属性都被强制为小写文本,因此任何Angular指令或属性都会失败.例如* ngIf,* ngFor,[formGroup],formControlName等… Angular使用camelCase几乎所有东西,因此一旦它被强制为小写文本,它就会被忽略,这种方法不再是一个可行的解决方案.

尝试2:这次我试图利用Angulars NgTemplateOutlet动态地将HTML添加到组件,然后创建并绑定到Reactive Form.这起初似乎是一个很好的解决方案,但最终为了让html呈现它需要使用[innerHTML]属性,再次使这个方法无用(如我第一次尝试中所述).

尝试3:最后我发现了动态组件,这个解决方案部分工作.我现在可以成功地创建一个格式良好的Angular HTML模板,该模板在浏览器中正确呈现.然而,这只解决了我的一半要求.此时HTML按预期显示,但我无法创建一个Reactive Form并绑定到输入.

ProblemI现在有一个动态组件,它生成HTML,其中包含我需要通过创建一个Reactive Form来绑定的输入.

尝试4:我尝试将所有逻辑用于在创建的动态组件中创建Reactive Form.

通过使用此方法,显示动态组件HTML,但是我收到一个新错误:“错误错误:formGroup需要一个FormGroup实例.请传入一个.”

StackBlitz with error scenario

解决方法

解决方案

Working StackBlitz with solution

解决方案是在父组件中创建Reactive Form.然后使用Angulars依赖注入并将父组件注入动态组件.

通过将父组件注入动态组件,您将可以访问所有父组件公共属性,包括反应形式.此解决方案演示了能够创建和使用Reactive Form绑定到动态生成的组件中的输入.

完整代码如下

import {
  Component,ViewChild,OnDestroy,AfterContentInit,ComponentFactoryResolver,Input,Compiler,ViewContainerRef,NgModule,NgModuleRef,Injector,Injectable
} from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import {
  ReactiveFormsModule,FormBuilder,FormGroup,FormControl,Validators
} from '@angular/forms';


@Injectable()
export class DynamicControlClass {
  constructor(public Key: string,public Validator: boolean,public minLength: number,public maxLength: number,public defaultValue: string,public requiredErrorString: string,public minLengthString: string,public maxLengthString: string,public ControlType: string
  ) { }
}

@Component({
  selector: 'app',templateUrl: './app.component.html',styleUrls: ['./app.component.css']
})
export class AppComponent implements AfterContentInit,OnDestroy {
  @ViewChild('dynamicComponent',{ read: ViewContainerRef }) _container: ViewContainerRef;
  public ackStringForm: FormGroup;
  public ctlClass: DynamicControlClass[];
  public formErrors: any = {};
  public group: any = {};
  public submitted: boolean = false;

  private cmpRef;

  constructor(
    private fb: FormBuilder,private componentFactoryResolver: ComponentFactoryResolver,private compiler: Compiler,private _injector: Injector,private _m: NgModuleRef<any>) {
    this.ctlClass = [
      new DynamicControlClass('formTextField',true,5,'','Please enter a value','Must be Minimum of 5 Characters','textbox')]
  }

  ngOnDestroy() {
    //Always destroy the dynamic component
    //when the parent component gets destroyed
    if (this.cmpRef) {
      this.cmpRef.destroy();
    }
  }

  ngAfterContentInit() {
    this.ctlClass.forEach(dyclass => {
      let minValue: number = dyclass.minLength;
      let maxValue: number = dyclass.maxLength;

      if (dyclass.Validator) {
        this.formErrors[dyclass.Key] = '';

        if ((dyclass.ControlType === 'radio') || (dyclass.ControlType === 'checkbox')) {
          this.group[dyclass.Key] = new FormControl(dyclass.defaultValue || null,[Validators.required]);
        }
        else {
          if ((minValue > 0) && (maxValue > 0)) {
            this.group[dyclass.Key] = new FormControl(dyclass.defaultValue || '',[Validators.required,<any>Validators.minLength(minValue),<any>Validators.maxLength(maxValue)]);
          }
          else if ((minValue > 0) && (maxValue === 0)) {
            this.group[dyclass.Key] = new FormControl(dyclass.defaultValue || '',<any>Validators.minLength(minValue)]);
          }
          else if ((minValue === 0) && (maxValue > 0)) {
            this.group[dyclass.Key] = new FormControl(dyclass.defaultValue || '',<any>Validators.maxLength(maxValue)]);
          }
          else if ((minValue === 0) && (maxValue === 0)) {
            this.group[dyclass.Key] = new FormControl(dyclass.defaultValue || '',[Validators.required]);
          }
        }
      }
      else {
        this.group[dyclass.Key] = new FormControl(dyclass.defaultValue || '');
      }
    });

    this.ackStringForm = new FormGroup(this.group);

    this.ackStringForm.valueChanges.subscribe(data => this.onValueChanged(data));

    this.onValueChanged();

    this.addComponent();
  }

  private addComponent() {
    let template = `  <div style="border: solid; border-color:green;">
                      <p>This is a dynamic component with an input using a reactive form </p>
                      <form [formGroup]="_parent.ackStringForm" class="form-row">
                      <input type="text" formControlName="formTextField"  required> 
                      <div *ngIf="_parent.formErrors.formTextField" class="alert alert-danger">
                      {{ _parent.formErrors.formTextField }}</div>
                      </form><br>
                      <button (click)="_parent.submitForm()"> Submit</button>
                      <br>
                      </div>
                      <br>
                      `;
    @Component({
      template: template,styleUrls: ['./dynamic.component.css']
    })
    class DynamicComponent {
      constructor(public _parent: AppComponent) {}
    }
    @NgModule({ 
      imports: [
        ReactiveFormsModule,BrowserModule
        ],declarations: [DynamicComponent] 
    })
    class DynamicComponentModule { }

    const mod = this.compiler.compileModuleAndAllComponentsSync(DynamicComponentModule);
    const factory = mod.componentFactories.find((comp) =>
      comp.componentType === DynamicComponent
    );
    const component = this._container.createComponent(factory);
  }

  private onValueChanged(data?: any) {
    if (!this.ackStringForm) { return; }
    const form = this.ackStringForm;

    for (const field in this.formErrors) {
      // clear previous error message (if any)
      this.formErrors[field] = '';
      const control = form.get(field);

      if ((control && control.dirty && !control.valid) || (this.submitted)) {

        let objClass: any;

        this.ctlClass.forEach(dyclass => {
          if (dyclass.Key === field) {
            objClass = dyclass;
          }
        });

        for (const key in control.errors) {
          if (key === 'required') {
            this.formErrors[field] += objClass.requiredErrorString + ' ';
          }
          else if (key === 'minlength') {
            this.formErrors[field] += objClass.minLengthString + ' ';
          }
          else if (key === 'maxLengthString') {
            this.formErrors[field] += objClass.minLengthString + ' ';
          }
        }
      }
    }
  }

  public submitForm(){
    let value = this.ackStringForm.value.formTextField;
    alert(value);
  }
}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读