首页 > 解决方案 > Angular:动态表单的问题

问题描述

我有一个我想要动态的子表单,即一个选择字段值更改另一个选择字段的内容并设置默认值(如果存在)。

依赖选择选项发生了很大变化,但修补默认值不起作用......

这是.ts:

    export interface GsmattFormValues {
    id: number,
    mattype: number,
    material: number,
}
@Component({
  selector: 'ngx-gsmatt',
  templateUrl: './gsmatt.component.html',
  styleUrls: ['./gsmatt.component.scss'],
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => GsmattComponent),
      multi: true
    },
    {
      provide: NG_VALIDATORS,
      useExisting: forwardRef(() => GsmattComponent),
      multi: true
    }
  ]
})
export class GsmattComponent implements OnInit, OnDestroy, ControlValueAccessor {

  @Input() inMandatoryObjects: any;
  @Input() inErrors: any[];

  mattypes: Mattype[];
  materials: Material[];

  allowMaterials: boolean = false;

  destroy$: Subject<boolean> = new Subject<boolean>();

  gsmattForm: FormGroup;

  constructor(
    private formBuilder: FormBuilder,
    public translate: TranslateService,
    ) { 
    }

  get f() { return this.gsmattForm.controls; }

/////////////////////////////////////////////////////////
////// OnInit & onDestroy
/////////////////////////////////////////////////////////
  ngOnInit(): void {
        this.mattypes=this.inMandatoryObjects['mattypes'];
        this.materials=this.inMandatoryObjects['materials'];
        this.initForm();
        this.gsmattForm.valueChanges.takeUntil(this.destroy$).subscribe(value => {
            this.onChange(value);
            this.onTouched();
        });
        
  }

  ngOnDestroy() {
    this.destroy$.next(true);
    this.destroy$.unsubscribe();
  }

//////////////////////////////////////////////////////////////////////////////
///// Control Value Accessor
//////////////////////////////////////////////////////////////////////////////

  get value(): GsmattFormValues {
    return this.gsmattForm.value;
  }

  set value(value: GsmattFormValues) {
    //if( value !== undefined && this.value !== value){ 
    if( value !== undefined ){      
        this.configureMatRCP(this.mattypes.find(item => item.id==value.mattype));
        this.gsmattForm.patchValue(value);
        this.onChange(value);
        this.onTouched();
    }
  }

  onChange: any = () => {}

  onTouched: any = () => {
  }

  // this method sets the value programmatically
  writeValue(value) {
    if (value) {
        this.value = value;
    }

    if (value === null) {
      this.gsmattForm.reset();
    }

  }

// upon UI element value changes, this method gets triggered
  registerOnChange(fn) {
    this.onChange = fn;
  }

// upon touching the element, this method gets triggered
  registerOnTouched(fn) {
    this.onTouched = fn;
  }

  // communicate the inner form validation to the parent form
  validate(_: FormControl) {
    return this.gsmattForm.valid ? null : { profile: { valid: false } };
  }

  get errors() {
    return this.gsmattForm.errors ? null : this.gsmattForm.errors;
  }


//////////////////////////////////////////////////////////////////////////////
///// Miscellaneous Functions
//////////////////////////////////////////////////////////////////////////////

  initForm() {
    this.gsmattForm = this.formBuilder.group({
        id: '',
        mattype: new FormControl('', [Validators.required, SelectedValue]),
        material: new FormControl(''),
    });
  }

/////////////////////////////////////////////////////////
////// Event Functions
/////////////////////////////////////////////////////////
  onMattypeChange(event) {
    var MATP;
    if (event) {MATP=this.mattypes.find(item => item.id==event);}
    console.log("UPDATING");
    this.configureMatRCP(MATP);
    this.setDfltValues(MATP);
  }

/////////////////////////////////////////////////////////
////// Dynamic Form Functions
/////////////////////////////////////////////////////////

  configureMatRCP(mattype?: Mattype) {
    console.log("FOrm "+JSON.stringify(this.gsmattForm.value));
    if (mattype) {
        this.materials=this.inMandatoryObjects['materials'].filter(item => item.mattype.id==mattype.id);
        if (this.materials.length>0) {
            this.gsmattForm.get("material").enable();
            this.allowMaterials=true;
        }
        else {
            this.gsmattForm.get("material").disable();
            this.allowMaterials=false;          
        }
    }
    else {
        this.allowMaterials=false;
        this.gsmattForm.get("material").disable();
    }

  }

  setDfltValues(mattype?: Mattype) {
    if (mattype) {
        var materialsTmp=this.inMandatoryObjects['materials'].filter(item => item.mattype.id==mattype.id);
        if (materialsTmp.length>0) {
            var dfltMaterial = materialsTmp.find(item => item.isdefault==true);
            console.log("DFLMATERIAL "+JSON.stringify(dfltMaterial));
            if (dfltMaterial) {console.log("BOOM "+dfltMaterial.id); 
                this.gsmattForm.patchValue({material: dfltMaterial.id});
            }
            else {this.gsmattForm.patchValue({material: ''});}
        }
        else {
            this.gsmattForm.patchValue({material: ''});     
        }
    }
    else {
        this.gsmattForm.patchValue({material: ''});
    }

  }

}

和html:

<div class="row">
  <div class="col-md-12">
    <nb-card>
      <nb-card-body>    
        <div [formGroup]="gsmattForm">
                  
          <input type="hidden" nbInput fullWidth id="id" formControlName="id"/>  
          <div class="row">
            <div class="col-sm-6">
              <div class="form-group">
                <label for="mattype" class="label">{{ 'MATTYPE' | translate }}</label>
                <nb-select id="mattype" formControlName="mattype" fullWidth status="basic"
                placeholder="{{ 'MATTYPE' | translate }}" (selectedChange)="onMattypeChange($event)">
                  <nb-option *ngFor="let option of mattypes" [value]="option.id">
                    {{ option.label | translate }}
                  </nb-option>
                </nb-select>
                <div *ngIf="f.mattype.touched && f.mattype.errors" class="invalid-feedback d-block">
                    <div *ngIf="f.mattype.errors['required']">{{ 'FIELD_REQUIRED' | translate: {field: 'MATTYPE' | translate} }}</div>
                </div>
              </div> 
            </div>
            <div class="col-sm-6" *ngIf="allowMaterials"> 
              <div class="form-group" >
                <label for="material" class="label">{{ 'MATERIAL' | translate }}</label>
                <nb-select id="material" formControlName="material" fullWidth status="{{ (f.material.errors && f.material.touched) ? 'danger': (!f.material.errors && f.material.touched) ? 'success' : 'basic' }}"
                    placeholder="{{ 'MATERIAL' | translate }}">
                    <nb-option *ngFor="let option of materials" [value]="option.id">
                        {{ option.label | translate }}
                    </nb-option>
                </nb-select>
                <div *ngIf="f.material.touched && f.material.errors" class="invalid-feedback d-block">
                    <div *ngIf="f.material.errors['required']">{{ 'FIELD_REQUIRED' | translate: {field: 'MATERIAL' | translate} }}</div>
                </div>
             </div>     
            </div>  
            </div>
        </div>      
      </nb-card-body>
    </nb-card>
  </div>
</div>

谢谢您的帮助

编辑 1:经过大量购买后,选择选项过滤和修补值之间似乎存在冲突。然后我尝试使用回调确保在设置值之前等待选择选项更新。

  configureMatRCP(setDfltValue: boolean, callback, mattype?: Mattype) {
    console.log("FOrm "+JSON.stringify(this.gsmattForm.value));
    if (mattype) {
        this.materials=this.inMandatoryObjects['materials'].filter(item => item.mattype.id==mattype.id);
        if (this.materials.length>0) {
            this.gsmattForm.get("material").enable();
            this.allowMaterials=true;
        }
        else {
            this.gsmattForm.get("material").disable();
            this.allowMaterials=false;          
        }

    }
    else {
        this.allowMaterials=false;
        this.gsmattForm.get("material").disable();
    }
    if(setDfltValue) {
        callback(mattype); 
    }

  }

  onMattypeChange(event) {
    var MATP;
    if (event) {MATP=this.mattypes.find(item => item.id==event);}
    console.log("UPDATING");
    this.configureMatRCP(true, this.setDfltValues(MATP), MATP);
    //this.setDfltValues(MATP);
  }

但我得到错误回调不是函数......我错过了什么?

标签: angularformsdynamic

解决方案


推荐阅读