【问题标题】:Angular 8: using ViewChild get a method result from a child to parent after that method is invoked in child componentAngular 8:在子组件中调用该方法后,使用 ViewChild 从子组件到父组件获取方法结果
【发布时间】:2020-01-11 07:27:40
【问题描述】:

在我的子组件中,我有两个按钮,如下所示:

child-component.html

<div>
   <button (click)="getFirstData()">First</button>
   <button (click)="getLastData()" >Last</button>
</div>

child-component.ts:

export class ChildComponent implements OnInit, AfterViewInit {
  firstItem: number;
  lastItem: number;

  constructor() {
  }

  ngOnInit() {
  }

  ngAfterViewInit(): void {
  }

  getFirstData() {
    this.firstItem = 1;
    return this.firstItem;
  }

  getLastData() {
    this.lastItem= 10;
    return this.lastItem;
  }

}

在父组件中,我需要在从子组件调用相应方法后接收firstItemlastItem 数据。当我尝试在 AfterViewInit 生命周期钩子中使用 ViewChild 在父组件中获取它时,如下所示:

parent-component.ts

export class ParentComponent implements OnInit, AfterViewInit {
  @ViewChild(ChildComponent, {static: true}) child: ChildComponent;

  first: number;
  last: number;

  ngOnInit() {
  }

  ngAfterViewInit() {

    console.log('first value ', this.child.getFirstData());
    console.log('last value ', this.child.getLastData());

  }

  getValues(): void {
    // some operations heer
  }
}

我无法从孩子那里获取这些数据。

我的目标是在按钮单击事件后在子项中调用方法后接收这些数据。并且收到后需要调用父组件中的getValues()方法。

我怎样才能做到这一点?

【问题讨论】:

  • 不要使用 ViewChild。使用输出。 angular.io/guide/…
  • @JBNizet 对于每个输出,我需要分别发出每个事件。假设我有三个或四个方法调用,那么我必须发出三个或四个事件发射器。在子选择器中,我必须声明它们中的每一个。我试图忽略这一点。另一方面,当我使用 ViewChild 时,我可以将整个组件放在一行中。
  • 不,你没有。例如,您可以使用单个输出并发出 { first: 1 }{ last: 10 }。当然,您也可以始终发出相同的值(例如未定义),然后使用 ViewChild 从子组件获取新状态,但您仍然不知道状态中刚刚发生了什么变化。

标签: angular viewchild


【解决方案1】:

示例 - Output decorator

子组件:

export class ChildComponent implements OnInit, AfterViewInit {
  firstItem: number;
  lastItem: number;

  @Output() firstItemChanged = new EventEmitter<number>();
  @Output() lastItemChanged = new EventEmitter<number>();

  constructor() {
  }

  ngOnInit() {
  }

  ngAfterViewInit(): void {
  }

  getFirstData() {
    this.firstItem = 1;
    this.firstItemChanged.emit(this.firstItem);
  }

  getLastData() {
    this.lastItem= 10;
    this.firstItemChanged.emit(this.lastItem);
  }

}

父组件html:

    <child-component (firstItemChanged)="handleFirstItemChanged($event)" (lastItemChanged)="handleLastItemChanged($event)"></child-component>

父组件:

export class ParentComponent {

  handleFirstItemChanged(value: number): void {
    // handle event
  }

  handleLastItemChanged(value: number): void {
    // handle event
  }
}

示例 - BehaviorSubject

子组件:

interface State {
  firstItem: number;
  lastItem: number;
}

export class ChildComponent {

  state = new BehaviorSubject<State>({
    firstItem: 0,
    lastItem: 0
  });

  constructor() { }

  firstButtonClicked() {
    const newState = this.state.value;
    newState.firstItem = 1;
    this.state.next(newState);
  }

  lastButtonClicked() {
    const newState = this.state.value;
    newState.lastItem = 1;
    this.state.next(newState);
  }
}

父组件:

export class ParentComponent implements AfterViewInit {

  @ViewChild(ChildComponent, {static: true}) child: ChildComponent;

  ngAfterViewInit(): void {
    this.child.state.subscribe(state => {
      // handle
    });
  }
}

【讨论】:

  • 我知道我可以使用输出装饰器。但是说,将来我需要发出更多的事件,然后我需要一次又一次地分别声明每个事件。但是使用 ViewChild,我可以将整个组件放在一行中。请使用 ViewChild 解决这个问题
  • 您可以创建一个 BehaviorSubject,当您单击按钮时会发出新值,并在父组件中订阅它。
  • 我用这种方法添加了一个例子
  • 这两种方法的不同之处仅在于您不能将@OutputBehaviorSubject 一起使用,并且EventEmitter 没有初始值。如果需要,那么您应该使用 Zepa 的第二种方法。鉴于EventEmitterSubject 的子类,您可以将状态对象与EventEmitter@Output 一起使用,因此您只有一个。就个人而言,我会走那条路,因为它是框架提出的,并且没有那么紧密耦合。
猜你喜欢
  • 2020-10-20
  • 2023-01-08
  • 2016-12-22
  • 2021-10-27
  • 2020-06-27
  • 1970-01-01
  • 2017-09-05
  • 2021-05-02
相关资源
最近更新 更多