Chiama il metodo del componente figlio dalla classe genitore - Angular


130

Ho creato un componente figlio che ha un metodo che voglio invocare.

Quando invoco questo metodo spara solo la console.log()linea, non imposterà la testproprietà ??

Di seguito è riportata l'app Angular di avvio rapido con le mie modifiche.

Genitore

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

Bambino

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';
    }
}

Come posso impostare anche la testproprietà?



Puoi controllare questa risposta qui: stackoverflow.com/a/53057589/6663458
Muhammad Mabrouk,

Risposte:


210

Puoi farlo usando @ViewChildper maggiori informazioni controlla questo link

Con selettore di tipo

componente figlio

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

componente genitore

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

  @ViewChild(ChildCmp) child:ChildCmp;

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

Con selettore di stringa

componente figlio

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

componente genitore

@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
Ho seguito il tuo approccio, ma ricevo un errore durante l'utilizzo delle direttive: [ChildCmp], L'errore dice: directives "non esiste nel tipo" Component ". L'ho cercato su Google e ho scoperto che le direttive sono deprecate in rc5. Quindi come gestirlo nella versione più recente. Per favore aiuto.
Waleed Shahzaib

1
prova questo link angular.io/guide/component-interaction e commenta il link delle direttive
rashfmnb

5
Come farlo funzionare quando ci sono più bambini della stessa classe ??
Anandhu Ajayakumar

@rashfmnb "Dichiarazione attesa". Si verifica un errore quando provo a scrivere @ViewChild ('child') child: ChildCmp; nel componente. Per favore aiuto! Inoltre, non posso importare lo stesso nella direttiva, mi dà un errore come "direttiva: (tipo di EmployeeProfileC ..." non è assegnabile al parametro di tipo "Componente". Il valore letterale dell'oggetto può specificare solo proprietà note e "direttiva" no esistono nel tipo "Component". "
Trilok Pathak

1
Questa è una risposta corretta, ma produce componenti strettamente accoppiati . Un modello migliore è usare le Inputproprietà: un osservabile a cui il bambino reagisce chiamando la propria funzione interna. Vedi la risposta di user6779899
Bogdan D

56

Questo ha funzionato per me! Per Angular 2, chiama il metodo del componente figlio nel componente padre

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
Che cos'è ChildVM in questa riga: @ViewChild (ChildComponent) child: ChildVM;
Waleed Shahzaib

@WaleedShahzaib Penso che OP intendesse ChildComponentperChildVM
Ajeet Shah

1
Pensavo che questo avrebbe creato un'istanza separata del componente, ma in realtà chiama la funzione dalla tua istanza con le sue variabili nello stato corrente di quel componente, vacca sacra! questo metodo è molto migliore della prima risposta!
tatsu

3
Ricevo sempre un valore indefinito di "this.child"
Ambuj Khanna

2
La mia ipotesi per "this.child" non è definito è che ViewChild stia indicando qualcosa che non esiste nel modello, o che tu stia tentando di accedervi troppo presto nel ciclo di vita, ad esempio nel costruttore.
tony

34

Penso che il modo più semplice sia usare Oggetto. Nel seguente codice di esempio il bambino riceverà una notifica ogni volta che viene chiamato "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);
  });
}

Esempio di lavoro su Stackblitz


4
È una soluzione elegante, tuttavia non funziona correttamente in tutti i casi, probabilmente a causa del mancato funzionamento del rilevamento del cambiamento angolare da iscrizione.
Alexei il

1
Ho trovato che questa è la soluzione migliore per il mio caso d'uso. Funziona come un fascino. Grazie!
Weston

Neat! Per i casi più semplici, è possibile evitare il sovraccarico Oggetto / Sottoscrizione passando un oggetto che ha un metodo di callback al bambino. Analogamente a quanto sopra, il bambino sovrascrive la richiamata per ricevere indicazioni dal genitore.
shr

@shr qualche possibilità puoi condividere la tua soluzione per passare un oggetto con richiamata?
Imad El Hitti

1
Questa è una soluzione elegante, questa dovrebbe essere la risposta accettata, basta cambiare il metodo di importazione come import {Subject} da 'rxjs';
VIKAS KOHLI

5

Angular: richiama il metodo del componente figlio nel modello del componente padre

Hai ParentComponent e ChildComponent che assomigliano a questo.

parent.component.html

inserisci qui la descrizione dell'immagine

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');
  }
}

Quando servi, assomiglia a questo:

inserisci qui la descrizione dell'immagine

Quando l'utente si concentra sull'elemento di input di ParentComponent, si desidera chiamare il metodo doSomething () di ChildComponent.

Fai semplicemente questo:

  1. Assegna al selettore figlio-app in parent.component.html un nome di variabile DOM (prefisso con # - hashtag) , in questo caso lo chiamiamo appChild.
  2. Assegna il valore dell'espressione (del metodo che vuoi chiamare) all'evento focus dell'elemento di input.

inserisci qui la descrizione dell'immagine

Il risultato:

inserisci qui la descrizione dell'immagine


OK, ma vogliamo anche farlo in modo programmatico utilizzando ts
canbax

Per l'uso dall'interno del componente: @ViewChild('appChild', { static: false }) appChild: ElementRef<HTMLElement>;e per un uso successivothis.appChild.doSomething()
Gil Epshtain

4

La risposta di user6779899 è chiara e più generica Tuttavia, sulla base della richiesta di Imad El Hitti, qui viene proposta una soluzione leggera. Può essere utilizzato quando un componente figlio è strettamente collegato a un solo genitore.

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

Considera il seguente esempio,

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

Maggiori informazioni su @ViewChild qui.


0

Avevo una situazione esatta in cui il componente padre aveva un Selectelemento in un modulo e al momento dell'invio, avevo bisogno di chiamare il metodo del componente figlio pertinente in base al valore selezionato dall'elemento select.

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

Spero che questo ti aiuti.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.