เรียกวิธีองค์ประกอบลูกจากคลาสแม่ - เชิงมุม


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
Muhammad Mabrouk

คำตอบ:


210

คุณสามารถทำได้โดยใช้@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] ข้อผิดพลาดระบุว่า: คำสั่ง 'ไม่มีอยู่ในประเภท' คอมโพเนนต์ ' ฉัน googled แล้วและพบว่าคำสั่งเลิกใช้งานใน rc5 ดังนั้นวิธีจัดการกับเวอร์ชันที่ใหม่กว่า กรุณาช่วย.
Waleed Shahzaib

1
ลองใช้ลิงก์นี้angular.io/guide/component-interactionและแสดงความคิดเห็นลิงก์คำสั่ง
rashfmnb

5
จะทำให้มันทำงานได้อย่างไรเมื่อมีเด็กหลายคนในชั้นเดียวกัน ??
Anandhu Ajayakumar

@rashfmnb "คาดว่าจะประกาศ" เกิดข้อผิดพลาดเมื่อฉันพยายามเขียน @ViewChild ('child') child: ChildCmp; ในคอมโพเนนต์ กรุณาช่วย! และนอกจากนี้ฉันไม่สามารถนำเข้าสิ่งเดียวกันในคำสั่งมันทำให้ฉันมีข้อผิดพลาดเช่น "directive: (typeof EmployeeProfileC ... " ไม่สามารถกำหนดให้กับพารามิเตอร์ประเภท 'Component' ได้ Object literal สามารถระบุคุณสมบัติที่รู้จักเท่านั้นและ 'directive' ไม่ได้ มีอยู่ในประเภท 'Component' "
ไตรโลกปฐก

1
คำตอบนี้เป็นคำตอบที่ถูกต้อง แต่สร้างส่วนประกอบที่เชื่อมต่อกัน รูปแบบที่ดีกว่าคือการใช้Inputคุณสมบัติ: สังเกตได้ซึ่งเด็กตอบสนองโดยการเรียกใช้ฟังก์ชันภายในของตัวเอง ดูคำตอบของผู้ใช้ 6779899
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 หมายChildComponentโดยChildVM
Ajeet ชาห์

1
ฉันคิดว่านี่จะสร้างอินสแตนซ์แยกต่างหากของส่วนประกอบ แต่จริงๆแล้วมันเรียกใช้ฟังก์ชันจากอินสแตนซ์ของคุณด้วยตัวแปรในสถานะปัจจุบันของส่วนประกอบนั้นวัวศักดิ์สิทธิ์! วิธีนี้ดีกว่าคำตอบแรก!
tatsu

3
ฉันมักจะได้รับค่าที่ไม่ได้กำหนดของ "this.child"
Ambuj Khanna

2
การคาดเดาของฉันสำหรับ 'this.child' ไม่ได้กำหนดไว้คือ ViewChild กำลังชี้ไปที่สิ่งที่ไม่มีอยู่ในเทมเพลตหรือคุณพยายามเข้าถึงเร็วเกินไปในวงจรชีวิตเช่นในตัวสร้าง
tony

34

ฉันคิดว่าวิธีที่ง่ายที่สุดคือการใช้เรื่อง ในโค้ดตัวอย่างร้องเด็กจะได้รับการแจ้งเตือนทุกครั้งที่มีการเรียก '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
เป็นวิธีการแก้ปัญหาที่ยอดเยี่ยมอย่างไรก็ตามมันทำงานไม่ถูกต้องในทุกกรณีอาจเป็นเพราะการตรวจจับการเปลี่ยนแปลงเชิงมุมไม่ทำงานจากการสมัครสมาชิก
Alexei

1
พบว่านี่เป็นทางออกที่ดีที่สุดสำหรับกรณีการใช้งานของฉัน ใช้งานได้เหมือนมีเสน่ห์ ขอบคุณ!
Weston

เรียบร้อย! สำหรับกรณีที่ง่ายกว่านี้คุณสามารถหลีกเลี่ยงค่าใช้จ่ายของ Subject / Subscribe ได้โดยส่งผ่านวัตถุที่มีวิธีการโทรกลับไปยังเด็ก คล้ายกับข้างต้นเด็กจะแทนที่การโทรกลับเพื่อรับข้อบ่งชี้จากผู้ปกครอง
shr

@ มีโอกาสใดที่คุณสามารถแบ่งปันวิธีแก้ปัญหาของคุณเพื่อส่งผ่านวัตถุด้วยการโทรกลับ?
Imad El Hitti

1
อันนี้เป็นวิธีแก้ปัญหาที่ยอดเยี่ยมซึ่งควรเป็นคำตอบที่ยอมรับได้เพียงแค่เปลี่ยนวิธีการนำเข้าเช่น import {Subject} จาก 'rxjs';
VIKAS

5

Angular - เรียกวิธีการของ Child Component ในเทมเพลตขององค์ประกอบหลัก

คุณมี 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 คุณต้องการเรียกเมธอด doSomething () ของ ChildComponent

เพียงทำสิ่งนี้:

  1. ให้ app-child selector ใน parent.component.html ชื่อตัวแปร DOM (นำหน้าด้วยแฮชแท็ก #)ในกรณีนี้เราเรียกว่า 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องค์ประกอบในรูปแบบและในการส่งฉันจำเป็นต้องเรียกใช้เมธอดของ Child-Component ที่เกี่ยวข้องตามค่าที่เลือกจากองค์ประกอบที่เลือก

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

หวังว่านี่จะช่วยได้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.