角度:ExpressionChangedAfterItHasBeenCheckedError

时间:2020-07-22 13:28:03

标签: angular

我有一个主要组件,该组件的窗体嵌入了几个子组件/窗体。

主要组件使用服务将数据重新发送到API服务器。该服务在主组件和子组件中都有我正在听的主题。

主要组件:

@Component({
  selector: 'zoomnew',
  templateUrl: './zoomnew.component.html',
  styleUrls: ['./zoomnew.component.scss']
})
export class ZoomnewComponent implements OnInit, OnDestroy {
  
  @ViewChild(ZoomFooComponent) ZoomFooComp: ZoomFooComponent;
  @ViewChild(ZoomBarComponent) ZoomBaromp: ZoomBarComponent;

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


  mandatObjSubscription: Subscription;
  mandatoryObjects: {
...
  } = {...};

  zoomForm: FormGroup;

  constructor(
    private zoomService: ZoomService,
    ) { }


/////////////////////////////////////////////////////////
////// OnInit & onDestroy
/////////////////////////////////////////////////////////
  ngOnInit() {
    
    this.initForm();
    
    this.mandatObjSubscription=this.zoomService.mandatObjSubject$.takeUntil(this.destroy$).subscribe(
        (data)=> {
            this.mandatoryObjects=data;
            this.setzoomDflt();
        },
    );

    this.onChanges();

  }

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


/////////////////////////////////////////////////////////
////// Form Functions
/////////////////////////////////////////////////////////

  initForm() {
    this.zoomForm = this.formBuilder.group({
      foo: new FormControl('', [Validators.required]),
      bar: new FormControl('', [Validators.required]),
    });
    
  }

  setzoomDflt() {
    this.zoomForm.patchValue({
      foo: this.fooDflt,
      bar: this.barDflt,
  };

}

我的一个子组件

@Component({
  selector: 'ngx-zoom-foo',
  templateUrl: './zoom-foo.component.html',
  styleUrls: ['./zoom-foo.component.scss'],
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => ZoomFooComponent),
      multi: true
    },
    {
      provide: NG_VALIDATORS,
      useExisting: forwardRef(() => ZoomFooComponent),
      multi: true
    }
  ]
})

export class ZoomFooComponent implements OnInit, OnDestroy, ControlValueAccessor {

  @Input() inEntityName: string;
  @Input() inErrors: any[];

  @ViewChild(ZoomFoolineComponent) FoolineComp: ZoomFoolineComponent;

  entityName: string;
  foos: Foo[];

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

  mandatObjSubscription: Subscription;
    
  zoomFooForm: FormGroup;

  constructor(
    private formBuilder: FormBuilder,
    private zoomService: ZoomService,
    ) { }



/////////////////////////////////////////////////////////
////// OnInit & onDestroy
/////////////////////////////////////////////////////////
  ngOnInit(): void {
        this.entityName= this.inEntityName;
        this.initForm();
        this.mandatObjSubscription=this.zoomService.mandatObjSubject$.takeUntil(this.destroy$).subscribe(
            objects => {
                this.foos=objects[this.entityName.toLowerCase()+'s'];
            }
        );
        this.zoomFooForm.valueChanges.takeUntil(this.destroy$).subscribe(value => {
            this.onChange(value);
            this.onTouched();
        });
        this.zoomService.emitMandatoryObjects();
  }

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

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

  get value(): Fooline[] {
    return this.zoomFooForm.value;
  }

  set value(value: Fooline[]) {
    //if( value !== undefined && this.value !== value){ 
    if( value !== undefined ){      
        this.getFoolines().clear();
        this.foos.forEach(foo => {
            const Entry = (value.find(item => item.id == foo.id))? value.find(item => item.id == foo.id): null;
            this.onAddFooline({
                id: foo.id,
                selected: (Entry)? Entry.selected : foo.bydefault,
                param: (Entry)? Entry.param : '',
                foo: foo,
            })
        })
        this.onChange(value);
        this.onTouched();
    }
  }

  onChange: any = () => {}

  onTouched: any = () => {}

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

    if (value === null) {
      this.zoomFooForm.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.zoomFooForm.valid ? null : { profile: { valid: false } };
  }

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


//////////////////////////////////////////////////////////////////////////////
/////* Form Functions
//////////////////////////////////////////////////////////////////////////////
  get f() { return this.zoomFooForm.controls; } 

  initForm() {
    this.zoomFooForm = this.formBuilder.group({
        foolines: this.formBuilder.array([]),
    });
  }
/////////////////////////////////////////////////////////
////// Gestion des add / remove fooline
/////////////////////////////////////////////////////////

  get foolines() {
    return this.zoomFooForm.get('foolines') as FormArray;
  }

  getFoolines(): FormArray {
    return this.zoomFooForm.get('foolines') as FormArray;
  }

  onAddFooline(foo) {
    this.getFoolines().push(this.formBuilder.control(foo, Validators.required));
  }

  onDelFooline(event) {
    this.getFoolines().removeAt(event.currentTarget.id);
  }

}

和HTML 主要

<ngx-zoom-foo id="fooComp" formControlName="foo"
    inEntityName="foo" [inErrors]="">
</ngx-zoom-foo>

子组件

<ng-container formArrayName="foolines" 
   *ngFor="let ctr of foolines.controls; let i=index">                  
   <ngx-zoom-fooline id="foo_{{ i }}" [formControlName]="i"            //ERROR HERE
        [inEntityName]="foo" [inErrors]="ctr.errors">
   </ngx-zoom-fooline>
</ng-container>

但是我收到一个错误:ExpressionChangedAfterItHaHasBeenCheckedError

感谢您的帮助

0 个答案:

没有答案