Bagaimana memanggil fungsi komponen lain di angular2

154

Saya memiliki dua komponen sebagai berikut dan saya ingin memanggil fungsi dari komponen lain. Kedua komponen termasuk dalam komponen induk ketiga menggunakan direktif.

Komponen 1:

@component(
    selector:'com1'
)
export class com1{
    function1(){...}
}

Komponen 2:

@component(
    selector:'com2'
)
export class com2{
    function2(){...
        // i want to call function 1 from com1 here
    }
}

Saya sudah mencoba menggunakan @inputdan @outputtetapi saya tidak mengerti persis bagaimana menggunakannya dan bagaimana memanggil fungsi itu, ada yang bisa membantu?

noobProgrammer
sumber

Jawaban:

130

Jika com1 dan com2 adalah saudara kandung yang dapat Anda gunakan

@component({
  selector:'com1',
})
export class com1{
  function1(){...}
}

com2 memancarkan acara menggunakan EventEmitter

@component({
  selector:'com2',
  template: `<button (click)="function2()">click</button>`
)
export class com2{
  @Output() myEvent = new EventEmitter();
  function2(){...
    this.myEvent.emit(null)
  }
}

Di sini komponen induk menambahkan acara yang mengikat untuk mendengarkan myEventacara dan kemudian memanggil com1.function1()ketika peristiwa seperti itu terjadi. #com1adalah variabel templat yang memungkinkan untuk merujuk ke elemen ini dari tempat lain di templat. Kami menggunakan ini untuk membuat function1()event handler untuk myEventdari com2:

@component({
  selector:'parent',
  template: `<com1 #com1></com1><com2 (myEvent)="com1.function1()"></com2>`
)
export class com2{
}

Untuk opsi lain untuk berkomunikasi antar komponen, lihat juga interaksi komponen

Günter Zöchbauer
sumber
Pertanyaan Anda tidak mengandung apa pun tentang orang tua-anak. Apa yang ingin Anda capai?
Günter Zöchbauer
ketika Anda mulai berkata "Di sini komponen induk menambahkan acara yang mengikat untuk mendengarkan myEvent", saya sangat bingung. Saya pikir kami sedang mencoba untuk menyelesaikan situasi komponen saudara kandung. Tautan bersudut adalah semua anak induk, jadi saya tidak bisa menggunakannya.
Angela P
Ini adalah orangtua dari saudara kandung (Anda juga dapat mengatakan host). <sibling1 (myEvent)="...">adalah acara yang mengikat untuk orang tua / host, karena itulah satu-satunya cara yang disediakan Angular. Namun event handler memanggil metode pada saudara lain ( com1). Orang tua digunakan sebagai mediator.
Günter Zöchbauer
Bagaimana cara menghindarinya? Di dalam somecomponent.ts?
Mohammad Kermani
Tetapi jika dua komponen berbeda (Acara Klik ((satu komponen)) untuk beberapa pengguna dalam daftar & salin kejadian klik pada halaman detail (komponen lain)) - Dari metode Satu Komponen yang ingin saya gunakan dalam komponen lain, bagaimana cara melakukannya Tolong beritahu aku ??? @ GünterZöchbauer
Jignesh Vagh
164

Pertama, apa yang Anda butuhkan untuk memahami hubungan antar komponen. Kemudian Anda dapat memilih metode komunikasi yang tepat. Saya akan mencoba menjelaskan semua metode yang saya tahu dan gunakan dalam praktik saya untuk komunikasi antar komponen.

Hubungan macam apa yang bisa terjadi antar komponen?

1. Induk> Anak

masukkan deskripsi gambar di sini

Berbagi Data melalui Input

Ini mungkin metode berbagi data yang paling umum. Ini bekerja dengan menggunakan @Input()dekorator untuk memungkinkan data dikirimkan melalui templat.

parent.component.ts

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

@Component({
  selector: 'parent-component',
  template: `
    <child-component [childProperty]="parentProperty"></child-component>
  `,
  styleUrls: ['./parent.component.css']
})
export class ParentComponent{
  parentProperty = "I come from parent"
  constructor() { }
}

child.component.ts

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

@Component({
  selector: 'child-component',
  template: `
      Hi {{ childProperty }}
  `,
  styleUrls: ['./child.component.css']
})
export class ChildComponent {

  @Input() childProperty: string;

  constructor() { }

}

Ini adalah metode yang sangat sederhana. Mudah digunakan. Kami juga dapat menangkap perubahan pada data dalam komponen anak menggunakan ngOnChanges .

Tetapi jangan lupa bahwa jika kita menggunakan objek sebagai data dan mengubah parameter objek ini, referensi untuk itu tidak akan berubah. Oleh karena itu, jika kita ingin menerima objek yang dimodifikasi dalam komponen anak, itu harus tidak berubah.

2. Anak> Orangtua

masukkan deskripsi gambar di sini

Berbagi Data melalui ViewChild

ViewChild memungkinkan satu komponen untuk disuntikkan ke yang lain, memberikan orang tua akses ke atribut dan fungsinya. Satu peringatan, bagaimanapun, adalah bahwa childtidak akan tersedia sampai setelah tampilan diinisialisasi. Ini berarti kita perlu mengimplementasikan kait siklus hidup AfterViewInit untuk menerima data dari anak.

parent.component.ts

import { Component, ViewChild, AfterViewInit } from '@angular/core';
import { ChildComponent } from "../child/child.component";

@Component({
  selector: 'parent-component',
  template: `
    Message: {{ message }}
    <child-compnent></child-compnent>
  `,
  styleUrls: ['./parent.component.css']
})
export class ParentComponent implements AfterViewInit {

  @ViewChild(ChildComponent) child;

  constructor() { }

  message:string;

  ngAfterViewInit() {
    this.message = this.child.message
  }
}

child.component.ts

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

@Component({
  selector: 'child-component',
  template: `
  `,
  styleUrls: ['./child.component.css']
})
export class ChildComponent {

  message = 'Hello!';

  constructor() { }

}

Berbagi Data melalui Output () dan EventEmitter

Cara lain untuk berbagi data adalah dengan memancarkan data dari anak, yang dapat didaftar oleh orang tua. Pendekatan ini sangat ideal ketika Anda ingin berbagi perubahan data yang terjadi pada hal-hal seperti klik tombol, entri formulir, dan acara pengguna lainnya.

parent.component.ts

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

@Component({
  selector: 'parent-component',
  template: `
    Message: {{message}}
    <child-component (messageEvent)="receiveMessage($event)"></child-component>
  `,
  styleUrls: ['./parent.component.css']
})
export class ParentComponent {

  constructor() { }

  message:string;

  receiveMessage($event) {
    this.message = $event
  }
}

child.component.ts

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

@Component({
  selector: 'child-component',
  template: `
      <button (click)="sendMessage()">Send Message</button>
  `,
  styleUrls: ['./child.component.css']
})
export class ChildComponent {

  message: string = "Hello!"

  @Output() messageEvent = new EventEmitter<string>();

  constructor() { }

  sendMessage() {
    this.messageEvent.emit(this.message)
  }
}

3. Saudara kandung

masukkan deskripsi gambar di sini

Anak> Orangtua> Anak

Saya mencoba menjelaskan cara lain untuk berkomunikasi antara saudara kandung di bawah ini. Tetapi Anda sudah bisa memahami salah satu cara memahami metode di atas.

parent.component.ts

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

@Component({
  selector: 'parent-component',
  template: `
    Message: {{message}}
    <child-one-component (messageEvent)="receiveMessage($event)"></child1-component>
    <child-two-component [childMessage]="message"></child2-component>
  `,
  styleUrls: ['./parent.component.css']
})
export class ParentComponent {

  constructor() { }

  message: string;

  receiveMessage($event) {
    this.message = $event
  }
}

child-one.component.ts

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

@Component({
  selector: 'child-one-component',
  template: `
      <button (click)="sendMessage()">Send Message</button>
  `,
  styleUrls: ['./child-one.component.css']
})
export class ChildOneComponent {

  message: string = "Hello!"

  @Output() messageEvent = new EventEmitter<string>();

  constructor() { }

  sendMessage() {
    this.messageEvent.emit(this.message)
  }
}

child-two.component.ts

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

@Component({
  selector: 'child-two-component',
  template: `
       {{ message }}
  `,
  styleUrls: ['./child-two.component.css']
})
export class ChildTwoComponent {

  @Input() childMessage: string;

  constructor() { }

}

4. Komponen Yang Tidak Terkait

masukkan deskripsi gambar di sini

Semua metode yang saya jelaskan di bawah ini dapat digunakan untuk semua opsi di atas untuk hubungan antar komponen. Tetapi masing-masing memiliki kelebihan dan kekurangan.

Berbagi Data dengan Layanan

Saat mengirimkan data antar komponen yang tidak memiliki koneksi langsung, seperti saudara kandung, cucu, dll, Anda harus menggunakan layanan bersama. Ketika Anda memiliki data yang harus selalu disinkronkan, saya menemukan bahwa RxJS BehaviorSubject sangat berguna dalam situasi ini.

data.service.ts

import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';

@Injectable()
export class DataService {

  private messageSource = new BehaviorSubject('default message');
  currentMessage = this.messageSource.asObservable();

  constructor() { }

  changeMessage(message: string) {
    this.messageSource.next(message)
  }

}

first.component.ts

import { Component, OnInit } from '@angular/core';
import { DataService } from "../data.service";

@Component({
  selector: 'first-componennt',
  template: `
    {{message}}
  `,
  styleUrls: ['./first.component.css']
})
export class FirstComponent implements OnInit {

  message:string;

  constructor(private data: DataService) {
      // The approach in Angular 6 is to declare in constructor
      this.data.currentMessage.subscribe(message => this.message = message);
  }

  ngOnInit() {
    this.data.currentMessage.subscribe(message => this.message = message)
  }

}

second.component.ts

import { Component, OnInit } from '@angular/core';
import { DataService } from "../data.service";

@Component({
  selector: 'second-component',
  template: `
    {{message}}
    <button (click)="newMessage()">New Message</button>
  `,
  styleUrls: ['./second.component.css']
})
export class SecondComponent implements OnInit {

  message:string;

  constructor(private data: DataService) { }

  ngOnInit() {
    this.data.currentMessage.subscribe(message => this.message = message)
  }

  newMessage() {
    this.data.changeMessage("Hello from Second Component")
  }

}

Berbagi Data dengan Rute

Terkadang Anda tidak hanya perlu mengirimkan data sederhana antar komponen tetapi juga menyimpan beberapa kondisi halaman. Misalnya, kami ingin menyimpan beberapa filter di pasar online dan kemudian menyalin tautan ini dan mengirim ke teman. Dan kami berharap untuk membuka halaman dalam kondisi yang sama seperti kami. Cara pertama, dan mungkin yang tercepat, untuk melakukan ini adalah dengan menggunakan parameter kueri .

Parameter kueri terlihat lebih di sepanjang garis di /people?id=mana iddapat sama dengan apa pun dan Anda dapat memiliki parameter sebanyak yang Anda inginkan. Parameter kueri akan dipisahkan oleh karakter ampersand.

Saat bekerja dengan parameter kueri, Anda tidak perlu mendefinisikannya dalam file rute Anda, dan mereka bisa dinamai parameter. Misalnya, ambil kode berikut:

page1.component.ts

import {Component} from "@angular/core";
import {Router, NavigationExtras} from "@angular/router";

@Component({
    selector: "page1",
  template: `
    <button (click)="onTap()">Navigate to page2</button>
  `,
})
export class Page1Component {

    public constructor(private router: Router) { }

    public onTap() {
        let navigationExtras: NavigationExtras = {
            queryParams: {
                "firstname": "Nic",
                "lastname": "Raboy"
            }
        };
        this.router.navigate(["page2"], navigationExtras);
    }

}

Di halaman penerimaan, Anda akan menerima parameter kueri ini seperti berikut:

page2.component.ts

import {Component} from "@angular/core";
import {ActivatedRoute} from "@angular/router";

@Component({
    selector: "page2",
    template: `
         <span>{{firstname}}</span>
         <span>{{lastname}}</span>
      `,
})
export class Page2Component {

    firstname: string;
    lastname: string;

    public constructor(private route: ActivatedRoute) {
        this.route.queryParams.subscribe(params => {
            this.firstname = params["firstname"];
            this.lastname = params["lastname"];
        });
    }

}

NgRx

Cara terakhir, yang lebih rumit tetapi lebih kuat, adalah menggunakan NgRx . Perpustakaan ini bukan untuk berbagi data; itu adalah perpustakaan manajemen negara yang kuat. Dalam contoh singkat saya tidak dapat menjelaskan cara menggunakannya, tetapi Anda dapat mengunjungi situs resmi dan membaca dokumentasi tentangnya.

Bagi saya, NgRx Store memecahkan banyak masalah. Misalnya, ketika Anda harus berurusan dengan yang dapat diobservasi dan ketika tanggung jawab untuk beberapa data yang dapat diamati dibagi antara komponen yang berbeda, tindakan toko dan peredam memastikan bahwa modifikasi data akan selalu dilakukan "dengan cara yang benar".

Ini juga menyediakan solusi yang andal untuk caching permintaan HTTP. Anda akan dapat menyimpan permintaan dan responsnya sehingga Anda dapat memverifikasi bahwa permintaan yang Anda buat belum memiliki respons tersimpan.

Anda dapat membaca tentang NgRx dan memahami apakah Anda membutuhkannya di aplikasi Anda atau tidak:

Akhirnya, saya ingin mengatakan bahwa sebelum memilih beberapa metode untuk berbagi data, Anda perlu memahami bagaimana data ini akan digunakan di masa depan. Maksud saya mungkin barusan Anda hanya dapat menggunakan @Inputdekorator untuk berbagi nama pengguna dan nama keluarga. Kemudian Anda akan menambahkan komponen baru atau modul baru (misalnya, panel admin) yang membutuhkan informasi lebih lanjut tentang pengguna. Ini berarti bahwa mungkin cara yang lebih baik untuk menggunakan layanan untuk data pengguna atau cara lain untuk berbagi data. Anda harus lebih memikirkannya sebelum mulai menerapkan berbagi data.

Roman Skydan
sumber
3
Penjelasan terbaik dengan contoh
afeef
1
jawaban terbaik untuk topik ini yang pernah saya lihat, selamat, ...
Lonely
Penjelasan Excelent
Moisés Aguilar
di 3. Bersaudara nama tampilan child-two.component.ts di html harus childMessage (untuk kasus ini gunakan file html)
Nam Nguyễn
84

Anda dapat mengakses metode komponen seseorang dari komponen dua ..

satu komponen

  ngOnInit() {}

  public testCall(){
    alert("I am here..");    
  }

komponenDua

import { oneComponent } from '../one.component';


@Component({
  providers:[oneComponent ],
  selector: 'app-two',
  templateUrl: ...
}


constructor(private comp: oneComponent ) { }

public callMe(): void {
    this.comp.testCall();
  }

file componentTwo html

<button (click)="callMe()">click</button>
Jayantha
sumber
2
Ini untuk saya sampai saya perlu misalnya mengakses variabel di componentOne dari componentTwo dengan memanggil testCall .... kasus di mana nilai variabel diatur oleh componentOne tetapi componentTwo akan mendapatkan default dan bukan arus.
rey_coder
2
Saya tidak mendapatkan nilai variabel componentOne di dalam ke metode testCall jika saya memanggil testCall dari componentTwo. Ada ide?
Raja
Tolong jelaskan metode ini untuk Ionic 4 dengan Angular 7
Mohammad Ayoub Khan
dengan cara ini tidak triger @Raja memiliki masalah yang sama
Kevin Dias
1
THQQQQQQQQQQQ SO MUCH MAN
Ashu
33

Komponen 1 (anak):

@Component(
  selector:'com1'
)
export class Component1{
  function1(){...}
}

Komponen 2 (induk):

@Component(
  selector:'com2',
  template: `<com1 #component1></com1>`
)
export class Component2{
  @ViewChild("component1") component1: Component1;

  function2(){
    this.component1.function1();
  }
}
Ihor Khomiak
sumber
Jawaban bagus, lihat juga di sini .
Cipher
oke bagaimana saya memanggil function2 di html? saya selalu mendapatkan this.component1 tidak terdefinisi
cajuuh
<com1 # component1 (klik) = "function2 ()"> </com1>
Ihor Khomiak
1
Ini bekerja untuk saya, setelah saya menyadari bahwa Anda harus mengimpor ViewChild dari @ angular / core dan juga Component1 dari mana pun itu.
Dallas Caley
1
Alih-alih memperluas kelas komponen, saya uesd @ViewChildyang bekerja untuk saya. Terima kasih untuk contoh ini.
Yash
27

Itu tergantung pada hubungan antara komponen Anda (orang tua / anak) tetapi cara terbaik / umum untuk membuat komponen berkomunikasi adalah dengan menggunakan layanan bersama.

Lihat dokumen ini untuk lebih jelasnya:

Yang sedang berkata, Anda bisa menggunakan yang berikut ini untuk memberikan instance dari com1 ke com2:

<div>
  <com1 #com1>...</com1>
  <com2 [com1ref]="com1">...</com2>
</div>

Di com2, Anda dapat menggunakan yang berikut ini:

@Component({
  selector:'com2'
})
export class com2{
  @Input()
  com1ref:com1;

  function2(){
    // i want to call function 1 from com1 here
    this.com1ref.function1();
  }
}
Thierry Templier
sumber
saya mendapatkan kesalahan Tidak dapat mengikat ke 'com1Ref' karena ini bukan properti asli yang dikenal
noobProgrammer
dan tidak menggunakan this.com1.function1 (); alih-alih this.com1ref.function1 ();
noobProgrammer
Terima kasih telah menunjukkan kesalahan ketik! Apakah Anda memiliki @Inputdi lapangan?
Thierry Templier
ok itu bekerja, bisakah kamu memberitahuku bagaimana mencapai yang sama untuk hubungan orangtua - anak ??
noobProgrammer
1
saya mencoba yang sama untuk anak induk tetapi katanya function1 () dari undegined
noobProgrammer
1
  • Katakanlah komponen pertama adalah DbstatsMainComponent
  • Komponen 2 DbstatsGraphComponent.
  • Komponen 1 memanggil metode ke-2

<button (click)="dbgraph.displayTableGraph()">Graph</button> <dbstats-graph #dbgraph></dbstats-graph>

Perhatikan variabel lokal #dbgraphpada komponen anak, yang dapat digunakan orang tua untuk mengakses metodenya ( dbgraph.displayTableGraph()).

RAHUL KUMAR
sumber
0

Menggunakan Dataservice kita dapat memanggil fungsi dari komponen lain

Component1: Komponen yang kita panggil fungsi

constructor( public bookmarkRoot: dataService ) { } 

onClick(){
     this.bookmarkRoot.callToggle.next( true );
}

dataervice.ts

import { Injectable } from '@angular/core';
@Injectable()
export class dataService {
     callToggle = new Subject();
}

Component2: Komponen yang berisi fungsi

constructor( public bookmarkRoot: dataService ) { 
  this.bookmarkRoot.callToggle.subscribe(( data ) => {
            this.closeDrawer();
        } )
} 

 closeDrawer() {
        console.log("this is called")
    }
Shafeeq Mohammed
sumber
ini mungkin memanggil beberapa kali untuk menghindari yang menggunakan kode ini di dalam konstruktorif ( this.bookmarkRoot.callToggle.observers.length === 0 ) { this.bookmarkRoot.callToggle.subscribe(( data ) => { this.closeDrawer(); } ) }
Shafeeq Mohammed