从父类调用子组件方法-Angular


130

我创建了一个子组件,该子组件具有要调用的方法。

当我调用此方法时,它仅触发该console.log()行,而不会设置该test属性?

下面是我的更改的快速入门Angular应用。

父母

import { Component } from '@angular/core';
import { NotifyComponent }  from './notify.component';

@Component({
    selector: 'my-app',
    template:
    `
    <button (click)="submit()">Call Child Component Method</button>
    `
})
export class AppComponent {
    private notify: NotifyComponent;

    constructor() { 
      this.notify = new NotifyComponent();
    }

    submit(): void {
        // execute child component method
        notify.callMethod();
    }
}

儿童

import { Component, OnInit } from '@angular/core';

@Component({
    selector: 'notify',
    template: '<h3>Notify {{test}}</h3>'
})
export class NotifyComponent implements OnInit {
   test:string; 
   constructor() { }

    ngOnInit() { }

    callMethod(): void {
        console.log('successfully executed.');
        this.test = 'Me';
    }
}

如何设置test属性?



您可以在此处查看此答案:stackoverflow.com/a/53057589/6663458
穆罕默德·马布罗克

Answers:


209

您可以通过使用@ViewChild以获取更多信息,请检查此链接

带类型选择器

子组件

@Component({
  selector: 'child-cmp',
  template: '<p>child</p>'
})
class ChildCmp {
  doSomething() {}
}

父组件

@Component({
  selector: 'some-cmp',
  template: '<child-cmp></child-cmp>',
  directives: [ChildCmp]
})
class SomeCmp {

  @ViewChild(ChildCmp) child:ChildCmp;

  ngAfterViewInit() {
    // child is set
    this.child.doSomething();
  }
}

带字符串选择器

子组件

@Component({
  selector: 'child-cmp',
  template: '<p>child</p>'
})
class ChildCmp {
  doSomething() {}
}

父组件

@Component({
  selector: 'some-cmp',
  template: '<child-cmp #child></child-cmp>',
  directives: [ChildCmp]
})
class SomeCmp {

  @ViewChild('child') child:ChildCmp;

  ngAfterViewInit() {
    // child is set
    this.child.doSomething();
  }
}

6
我遵循了您的方法,但是在使用指令[ChildCmp]时遇到错误,错误提示:'Component'类型中不存在指令'。我用谷歌搜索,发现指令在rc5中已被弃用。那么如何在较新的版本上处理它。请帮忙。
Waleed Shahzaib,

1
试试这个链接angular.io/guide/component-interaction并注释指令链接
rashfmnb

5
当有多个同班孩子时,如何使其工作?
Anandhu Ajayakumar,

@rashfmnb“需要声明”。当我尝试在组件中编写@ViewChild('child')child:ChildCmp;时,将出现错误。请帮忙!而且我也无法在指令中导入相同的内容,它给我带来诸如“指令:(typeof EmployeeProfileC ...'的错误,无法分配给'Component'类型的参数。对象文字只能指定已知的属性,而'指令'不能指定存在于“组件”类型中。”
Trilok Pathak '18

1
这是正确的答案,但是会产生紧密耦合的组件。更好的模式是使用Input属性:孩子可以通过调用其自己的内部函数对其作出反应的可观察性。查看user6779899的答案
Bogdan D

56

这对我有用!对于Angular 2,在父组件中调用子组件方法

Parent.component.ts

    import { Component, OnInit, ViewChild } from '@angular/core';
    import { ChildComponent } from '../child/child'; 
    @Component({ 
               selector: 'parent-app', 
               template: `<child-cmp></child-cmp>` 
              }) 
    export class parentComponent implements OnInit{ 
        @ViewChild(ChildComponent ) child: ChildComponent ; 

        ngOnInit() { 
           this.child.ChildTestCmp(); } 
}

Child.component.ts

import { Component } from '@angular/core';
@Component({ 
  selector: 'child-cmp', 
  template: `<h2> Show Child Component</h2><br/><p> {{test }}</p> ` 
})
export class ChildComponent {
  test: string;
  ChildTestCmp() 
  { 
    this.test = "I am child component!"; 
  }
 }


4
这行中的ChildVM是什么:@ViewChild(ChildComponent)child:ChildVM;
Waleed Shahzaib

@WaleedShahzaib我认为OP的意思ChildComponentChildVM
Ajeet Shah

1
我以为这会创建一个单独的组件实例,但是实际上它从您的实例中调用了该函数,并且该变量处于该组件的当前状态下,圣牛!这种方法比第一个答案更好!
tatsu

3
我总是得到“ this.child”的不确定值
Ambuj Khanna,

2
我对“ this.child”未定义的猜测是,要么ViewChild指向模板中不存在的内容,要么您试图在生命周期中(例如在构造函数中)过早地访问它。
Tony,

34

我认为最简单的方法是使用Subject。在下面的示例代码中,每次调用“ tellChild”都会通知孩子。

Parent.component.ts

import {Subject} from 'rxjs/Subject';
...
export class ParentComp {
    changingValue: Subject<boolean> = new Subject();
    tellChild(){
    this.changingValue.next(true);
  }
}

Parent.component.html

<my-comp [changing]="changingValue"></my-comp>

Child.component.ts

...
export class ChildComp implements OnInit{
@Input() changing: Subject<boolean>;
ngOnInit(){
  this.changing.subscribe(v => { 
     console.log('value is changing', v);
  });
}

Stackblitz上的工作样本


4
这是一个优雅的解决方案,但是在所有情况下都无法正常工作,这可能是由于Angular更改检测无法通过订阅起作用。
阿列克谢

1
发现这是我用例的最佳解决方案。奇迹般有效。谢谢!
韦斯顿

干净!对于更简单的情况,可以通过将具有回调方法的对象传递给子级来避免“主题/订阅”开销。与上述类似,子级重写回调以从父级接收指示。
shr

@shr是否有机会共享您的解决方案以通过回调传递对象?
Imad El Hitti,

1
这是一个很好的解决方案,应该是公认的答案,只需更改导入方法,例如从'rxjs'导入import {Subject};
VIKAS KOHLI '19

5

Angular –在父组件模板中调用子组件的方法

您具有如下所示的ParentComponent和ChildComponent。

parent.component.html

在此处输入图片说明

parent.component.ts

import {Component} from '@angular/core';

@Component({
  selector: 'app-parent',
  templateUrl: './parent.component.html',
  styleUrls: ['./parent.component.css']
})
export class ParentComponent {
  constructor() {
  }
}

child.component.html

<p>
  This is child
</p>

child.component.ts

import {Component} from '@angular/core';

@Component({
  selector: 'app-child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.css']
})
export class ChildComponent {
  constructor() {
  }

  doSomething() {
    console.log('do something');
  }
}

投放时,它看起来像这样:

在此处输入图片说明

当用户专注于ParentComponent的输入元素时,您要调用ChildComponent的doSomething()方法。

只需执行以下操作:

  1. 在parent.component.html中为app-child选择器指定一个DOM变量名 (带#的前缀 -hashtag ,在这种情况下,我们将其称为appChild。
  2. 将表达式值(要调用的方法的值)分配给输入元素的焦点事件。

在此处输入图片说明

结果:

在此处输入图片说明


好的,但是我们也想使用ts进行编程
canbax

在组件内部使用:@ViewChild('appChild', { static: false }) appChild: ElementRef<HTMLElement>;以后使用this.appChild.doSomething()
Gil Epshtain,

4

user6779899的回答很简洁而且更通用。但是,根据Imad El Hitti的要求,这里提出了一种轻量级的解决方案。当子组件仅与一个父组件紧密连接时,可以使用此功能。

Parent.component.ts

export class Notifier {
    valueChanged: (data: number) => void = (d: number) => { };
}

export class Parent {
    notifyObj = new Notifier();
    tellChild(newValue: number) {
        this.notifyObj.valueChanged(newValue); // inform child
    }
}

Parent.component.html

<my-child-comp [notify]="notifyObj"></my-child-comp>

Child.component.ts

export class ChildComp implements OnInit{
    @Input() notify = new Notifier(); // create object to satisfy typescript
    ngOnInit(){
      this.notify.valueChanged = (d: number) => {
            console.log(`Parent has notified changes to ${d}`);
            // do something with the new value 
        };
    }
 }

2

考虑以下示例,

    import import { AfterViewInit, ViewChild } from '@angular/core';
    import { Component } from '@angular/core';
    import { CountdownTimerComponent }  from './countdown-timer.component';
    @Component({
        selector: 'app-countdown-parent-vc',
        templateUrl: 'app-countdown-parent-vc.html',
        styleUrl: [app-countdown-parent-vc.css]
    export class CreateCategoryComponent implements OnInit {
         @ViewChild(CountdownTimerComponent, {static: false})
         private timerComponent: CountdownTimerComponent;
         ngAfterViewInit() {
             this.timerComponent.startTimer();
         }

         submitNewCategory(){
            this.ngAfterViewInit();     
         }

在此处阅读有关@ViewChild的更多信息。


0

我有一个确切的情况,父组件Select在表单中有一个元素,并且在提交时,我需要根据从select元素中选择的值来调用相关的Child-Component的方法。

Parent.HTML:

<form (ngSubmit)='selX' [formGroup]="xSelForm">
    <select formControlName="xSelector">
      ...
    </select>
<button type="submit">Submit</button>
</form>
<child [selectedX]="selectedX"></child>

家长:

selX(){
  this.selectedX = this.xSelForm.value['xSelector'];
}

Child.TS:

export class ChildComponent implements OnChanges {
  @Input() public selectedX;

  //ngOnChanges will execute if there is a change in the value of selectedX which has been passed to child as an @Input.

  ngOnChanges(changes: { [propKey: string]: SimpleChange }) {
    this.childFunction();
  }
  childFunction(){ }
}

希望这可以帮助。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.