提问者:小点点

ngIF的组件初始化不触发ngOnInit


我有一个父组件和一些子组件,这些子组件根据ngIf评估进行渲染。

我在Angular 8.1.3上

父组件

import { ActivatedRoute } from '@angular/router';
import {FirstStageViewComponent} from "src/app/first-stage-view/first-stage-view.component";
import {SecondStageViewComponent} from "src/app/second-stage-view/second-stage-view.component";
import {SecondStageFormComponent} from "src/app/second-stage-form/second-stage-form.component";
import {ThirdStageFormComponent} from "src/app/third-stage-form/third-stage-form.component";
import {ThirdStageViewComponent} from "src/app/third-stage-view/third-stage-view.component";
import { ProdService } from "src/app/service/prod-service";


@Component({
  selector: 'app-prod-view',
  templateUrl: './prod-view.component.html',
  styleUrls: ['./prod-view.component.css']
})
export class ProdViewComponent implements OnInit 
{

  id;
  _stage: string;
  constructor(private prodService: ProdService, private route: ActivatedRoute) { }

  ngOnInit() {

    this.route.params.subscribe(params => this.id=params.id);

    this.prodService.get(this.id).subscribe((data: string) => (this._stage = data["_stage"]),
                                           error => (console.log(error)));

  }

  talkBack(_updatedStage: string) {

    this._stage=_updatedStage;
  }

}

和它的模板

<div class="container">


    <div *ngIf="_stage>0">
        <app-first-stage-view [id]=id></app-first-stage-view>
    </div>

    <div *ngIf="_stage==1 else stage2">
        <app-second-stage-form [id]=id (talk)=talkBack($event)></app-second-stage-form>
    </div>
    <ng-template #stage2>
    <div *ngIf="_stage>1">
        <app-second-stage-view [id]=id></app-second-stage-view>
    </div>
    </ng-template>


    <div *ngIf="_stage==2 else stage3">
        <app-third-stage-form [id]=id (talk)=talkBack($event)></app-third-stage-form>
    </div>
    <ng-template #stage3>
    <div *ngIf="_stage>2">
        <app-third-stage-view [id]=id></app-third-stage-view>
    </div>
    </ng-template>
</div>

这是第二个子组件(未正确初始化的组件)

import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
import { FormGroup, FormBuilder, FormArray, Validators } from "@angular/forms";
import { ThirdStageService } from "src/app/service/third-stage.service";

@Component( {
    selector: 'app-third-stage-form',
    templateUrl: './third-stage-form.component.html',
    styleUrls: ['./third-stage-form.component.css']
} )
export class ThirdStageFormComponent implements OnInit {

    tsForm: FormGroup;
    @Input() id: string;
    @Output() talk: EventEmitter<string> = new EventEmitter<string>();

    constructor( private tsService: ThirdStageService,
        private formBuilder: FormBuilder ) {}

    ngOnInit() {
        this.tsForm = this.formBuilder.group( {
            ingredient: "TEST"
        } );

    }

}

和一个缩小的测试模板

<div class="container">
    <form [formGroup]="tsForm" (ngSubmit)="onSubmit()">
        <div class="form-group">
            <label for="name">{{ tsForm.controls[0].value }}</label> <input type="text"
                class="form-control" id="ingredient" formControlName="ingredient"
                required>
        </div>
    </form>
</div>

父级从服务器检索_stage值,第一个子级正确显示
然后该组件通过EventEmitter将新的阶段值反馈给其父级,父级相应地更新其变量的值
新值(2)实际上将我的第二个ngIf转换为true,并且第二个子构造函数(称为第三阶段形式,请不要混淆)被调用。但它不着火
默认值“TEST”没有显示在我的输入字段中,通过Augury检查组件树,我可以看到构造函数注入的两个依赖项存在,而在ngOnInit中创建的formgroup则不存在
如果我创建一个直接指向子组件的新路由,则一切都会按预期进行。


共2个答案

匿名用户

您使用的是异步的可观察对象。当请求完成时,将调用subscribe()中的任何内容,这可以在任何时候发生。

所以,你的就是这个。id是在您已经在第二个可观察对象上调用subscribe之后设置的。您需要使用一些确保订阅顺序的映射,如concatMap()

 ngOnInit() {
  this.route.params.pipe(
    concatMap(params => this.prodService.get(params.id))
  )
}

匿名用户

哈维尔,当你写作的时候

this.route.params.subscribe(params => this.id=params.id);
//here this.id has no value
this.prodService.get(this.id).subscribe(...)

你需要使用swithMap

this.route.params.pipe(
  switchMap((params)=>{ 
    //here you has "params" 
    this.id=params.id
    //we want return 
    return this.prodService.get(this.id)
  })
  ).subscribe((data: string) => (this._stage = data["_stage"]),
              error => (console.log(error))
  );