首页 > 解决方案 > 通过 @ViewChild 在视图中调用组件上的方法到 QueryList

问题描述

我想做一个可重用的组件,设置多个子组件并一次渲染一个组件,我在父组件处使用@ContenChildren 获得了一组视图,如下所示:

@ContentChildren(ChildComponent) children: QueryList<ChildComponent>;

//getCurrentChild function
getCurrentChild(){
   //index is a position of child
   return this.children.toArray()[this.index];
}  

并渲染父模板:

<ng-container *ngTemplateOutlet="getCurrentChild().content"></ng-container>

使用@ViewChild 在子组件中呈现内容:

@ViewChild('currentChild') child;

模板如下所示:

<ng-template #currentChild>
  <ng-content>
  </ng-content>
</ng-template>

当我想实现这个结构时,我会做这样的事情:

<parent>
    <child>
       <specific-one></specific-one>
    </child>
    <child>
       <specific-two></specific-two>
    </child>
</parent>

现在我在父组件中有一个方法,该方法在单击按钮上触发,并且需要调用特定组件中的方法(具体一个或具体两个取决于 currentChild):

export class SpecificOneComponent implements OnInit{

      action(){
          //this action will be called when parent is clicked
      }

}

我试过通过孩子调用方法reference,但动作没有退出。也传递了一个上下文,也没有传递。看起来我在父模板中设置内容的方式不正确。

任何帮助将不胜感激。

标签: javascriptangular

解决方案


ng-template每个子组件都有自己的内容,因此这意味着只获取对ng-content.

此外,由于您希望在父级发生特定事件时调用特定组件的方法,因此我们将使用服务以便能够通知特定组件。

具体的.service.ts

  private _shouldCallAction$ = new Subject();
  shouldCallAction$ = this._shouldCallAction$.asObservable();

  constructor() { }

  triggerAction (uniqueCompId) {
    this._shouldCallAction$.next(uniqueCompId);
  }

具体-{一个|两个|...n}.component.ts

这适用于依赖于父组件中发生的某些事件的每个组件。

  private shouldCallActionSubscription: Subscription;

  uniqueId: number | string;

  constructor(private specificService: SpecificService) {
    this.uniqueId = randomId();
  }

  ngOnInit() {
    this.shouldCallActionSubscription = this.specificService.shouldCallAction$
      .pipe(
        filter(id => id === this.uniqueId)
      )
      .subscribe(() => {
        console.log('calling action for specific-one')
      });
  }

  ngOnDestroy () {
    this.shouldCallActionSubscription.unsubscribe();
  }

child.component.html

<ng-container *ngIf="instanceIdx === crtIdx">
  <h3>trigger action of current specific component</h3>
  <button (click)="triggerAction()">trigger</button>
</ng-container>

<ng-template #currentChild>
  <ng-content></ng-content>
</ng-template>

child.component.ts

在这里,您还需要获取对 的引用specificComponent才能获得其唯一的 id

// Before class
let instances = 0;

@ViewChild('currentChild', { static: true }) tpl: TemplateRef<any>;
@ContentChild('specific', { static: true }) specificComp;

  get uniqueSpecificCompId () {
    return this.specificComp.uniqueId;
  }

  constructor (private specificService: SpecificService) {
    this.instanceIdx = instances++;
  }

  triggerAction () {

    this.specificService.triggerAction(this.uniqueSpecificCompId);
  }

父组件.ts

  @ViewChildren(ChildOneComponent) children: QueryList<ChildOneComponent>;
  @ViewChild('container', { static: true, read: ViewContainerRef }) container: ViewContainerRef;

  crtIdx = 0;

  ngAfterViewInit () {
    this.setNewView();
  }

  setNewView () {
    this.container.clear();

    this.container.createEmbeddedView(this.children.toArray()[this.crtIdx].tpl);
  }

  updateIndex (idx) {
    this.crtIdx = idx;

    this.setNewView();
  }

父组件.html

<app-child [crtIdx]="crtIdx">
 <!-- ... -->
 <app-specific-two #specific></app-specific-two>
</app-child> 
<app-child [crtIdx]="crtIdx">
 <!-- ... -->
 <app-specific-one #specific></app-specific-one>
</app-child> 

<ng-container #container></ng-container>

<h3>Select a child</h3>

<button
  *ngFor="let _ of [].constructor(n); let idx = index;"
  (click)="updateIndex(idx)"
> 
  Select {{ idx + 1 }}
</button>

这是演示

祝你好运!


推荐阅读