【问题标题】:Call child component method from parent class - Angular从父类调用子组件方法 - Angular
【发布时间】:2016-12-22 19:52:57
【问题描述】:

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

当我调用此方法时,它只会触发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 属性?

【问题讨论】:

标签: angular typescript angular-components


【解决方案1】:

您可以通过使用@ViewChild 来执行此操作以获取更多信息,请查看此link

带类型选择器

子组件

@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();
  }
}

【讨论】:

  • 我遵循了您的方法,但是在使用指令时出现错误:[ChildCmp],错误说:指令'在'组件'类型中不存在。我用谷歌搜索了它,发现指令在 rc5 中已被弃用。那么如何在较新的版本上处理它。请帮忙。
  • 试试这个链接angular.io/guide/component-interaction并评论指令链接
  • 同班有多个孩子时如何让它工作??
  • @rashfmnb“预期声明”。当我尝试在组件中编写 @ViewChild('child') child:ChildCmp; 时出现错误。请帮忙!而且我也不能在指令中导入相同的内容,它给了我类似“指令:(typeof EmployeeProfileC ...”的错误不能分配给“组件”类型的参数。对象文字只能指定已知属性,而“指令”不存在于“组件”类型中。”
  • 这是一个正确的答案,但它会产生紧密耦合的组件。更好的模式是使用Input 属性:一个可观察对象,孩子通过调用其自己的 内部函数对其做出反应。查看 user6779899 的回答
【解决方案2】:

这对我有用!对于 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!"; 
  }
 }

【讨论】:

  • 此行中的 ChildVM 是什么:@ViewChild(ChildComponent) child: ChildVM;
  • @WaleedShahzaib 我认为 OP 的意思是 ChildComponent ChildVM
  • 我认为这会创建一个单独的组件实例,但它实际上从您的实例调用函数,其变量处于该组件的当前状态,天哪!这个方法比第一个答案好多了!
  • 我总是得到“this.child”的未定义值
  • 我对 'this.child' 未定义的猜测是 ViewChild 指向模板中不存在的东西,或者您试图在生命周期中过早访问它,例如在构造函数中。
【解决方案3】:

我认为最简单的方法是使用主题。在下面的示例代码中,每次调用 '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 上的工作示例

【讨论】:

  • 这是一个优雅的解决方案,但它并非在所有情况下都能正常工作,可能是由于 Angular 更改检测无法从订阅中工作。
  • 发现这是我用例的最佳解决方案。奇迹般有效。谢谢!
  • 整洁!对于更简单的情况,您可以通过将具有回调方法的对象传递给子对象来避免主题/订阅开销。与上面类似,子级覆盖回调以接收来自父级的指示。
  • @shr 您是否有机会分享您的解决方案以通过回调传递对象?
  • 这是一个优雅的解决方案,这应该是公认的答案,只需更改导入方法,如 import {Subject} from 'rxjs';
【解决方案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 
        };
    }
 }

【讨论】:

    【解决方案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 以编程方式完成
    • 在组件内使用:@ViewChild('appChild', { static: false }) appChild: ElementRef&lt;HTMLElement&gt;; 及以后使用this.appChild.doSomething()
    【解决方案6】:

    考虑以下示例,

    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, AfterViewInit {
        @ViewChild(CountdownTimerComponent, {static: false}) private timerComponent: CountdownTimerComponent;
        ngAfterViewInit() {
            this.timerComponent.startTimer();
        }
    
        submitNewCategory(){
            this.ngAfterViewInit();
        }
    }
    

    Read more about @ViewChild here.

    【讨论】:

    • 这是最好的答案。
    • 无需显式调用 ngAfterViewInit()。如果在类上实现它会自动调用
    • 需要显式调用ngAfterViewInit(),因为我们需要显式告诉Angular调用方法startTimer(),它在组件CountdownTimerComponent
    【解决方案7】:

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

    父.HTML:

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

    Parent.TS:

    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(){ }
    }
    

    希望这会有所帮助。

    【讨论】:

      【解决方案8】:

      parent.component.html

      <app-child #childComponent></app-child>
      

      parent.component.ts

      @Component({
          selector: 'app-parent',
          templateUrl: './app-parent.component.html',
          styleUrls: ['./app-parent.component.scss']
      })
      export class ParentComponent {
          @ViewChild('childComponent', {static: false}) childComponent: ChildComponent;
      
          anyMethod(): void {
              childComponent.updateData() // updateData is a child method
          }
      }
      

      child.component.ts

      @Component({
          selector: 'app-child',
          templateUrl: './app-child.component.html',
          styleUrls: ['./app-child.component.scss']
      })
      export class ChildComponent {
          updateData(): void {
            // Method code goes here
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2020-10-20
        • 2023-01-08
        • 2020-12-22
        • 1970-01-01
        • 2017-04-22
        • 2017-12-15
        • 1970-01-01
        • 2017-09-05
        相关资源
        最近更新 更多