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

sha*_*urg 94 typescript angular-components angular

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

当我调用这个方法时它只会触发该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();
    }
}
Run Code Online (Sandbox Code Playgroud)

儿童

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';
    }
}
Run Code Online (Sandbox Code Playgroud)

我怎样才能设置test属性?

ras*_*mnb 147

您可以通过使用@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();
  }
}
Run Code Online (Sandbox Code Playgroud)

用字符串选择器

@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();
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 我按照你的方法,但我在使用指令时遇到错误:[ChildCmp],错误说:指令'在类型'组件'中不存在.我用Google搜索了它,发现指令在rc5中已弃用.那么如何在较新的版本上处理它.请帮忙. (4认同)
  • 这是一个正确的答案,但它会产生_紧密耦合的组件_。更好的模式是使用“Input”属性:子级通过调用其_own_内部函数对其做出反应的可观察值。参见用户6779899的回答 (4认同)
  • 当有多个同班孩子时,如何使其工作? (2认同)
  • 这里的一个问题是子组件是否在 *ngIf 中。当满足 *ngIf 条件时,ViewChild 的类型是 ElementRef 而不是“ChildCmp”或其他类型。作为 ElementRef,您无法调用该方法。 (2认同)

小智 38

这对我有用!对于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(); } 
}
Run Code Online (Sandbox Code Playgroud)

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!"; 
  }
 }
Run Code Online (Sandbox Code Playgroud)

  • 这一行中的ChildVM是什么:@ViewChild(ChildComponent)child:ChildVM; (4认同)
  • 我总是得到“this.child”的未定义值 (3认同)
  • 我对 'this.child' 未定义的猜测是 ViewChild 指向模板中不存在的东西,或者您试图在生命周期中过早地访问它,例如在构造函数中。 (2认同)

小智 19

父组件.html

<app-child #childComponent></app-child>
Run Code Online (Sandbox Code Playgroud)

父组件.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
    }
}
Run Code Online (Sandbox Code Playgroud)

子组件.ts

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

  • 我自己的问题的解决方案:`import {ChildComponent} from './whateverpath/child.component`。这是最简单的。受到推崇的! (2认同)

小智 18

我认为最简单的方法是使用Subject.在下面的示例代码中,每次调用'tellChild'时都会通知子项.

Parent.component.ts

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

Parent.component.html

<my-comp [changing]="changingValue"></my-comp>
Run Code Online (Sandbox Code Playgroud)

Child.component.ts

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

  • 这是一个优雅的解决方案,但它在所有情况下都无法正常工作,可能是由于Angular更改检测无法通过订阅工作. (4认同)
  • 这是一个优雅的解决方案,这应该是公认的答案,只需更改导入方法,例如 import {Subject} from 'rxjs'; (2认同)

小智 13

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

您有如下所示的 ParentComponent 和 ChildComponent。

父组件.html

在此处输入图片说明

父组件.ts

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

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

子组件.html

<p>
  This is child
</p>
Run Code Online (Sandbox Code Playgroud)

子组件.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');
  }
}
Run Code Online (Sandbox Code Playgroud)

服务时,它看起来像这样:

在此处输入图片说明

当用户关注 ParentComponent 的 input 元素时,您想要调用 ChildComponent 的 doSomething() 方法。

只需这样做:

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

在此处输入图片说明

结果:

在此处输入图片说明

  • 好的,但我们也想使用 ts 以编程方式完成此操作 (2认同)

shr*_*shr 8

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

父组件.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
    }
}
Run Code Online (Sandbox Code Playgroud)

父组件.html

<my-child-comp [notify]="notifyObj"></my-child-comp>
Run Code Online (Sandbox Code Playgroud)

子组件.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 
        };
    }
 }
Run Code Online (Sandbox Code Playgroud)


lwa*_*ore 5

考虑下面的例子,

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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