Açısal2'de başka bir bileşen işlevi nasıl çağrılır


154

Aşağıdaki gibi iki bileşen var ve başka bir bileşen bir işlevi çağırmak istiyorum. Her iki bileşen de yönerge kullanılarak üçüncü ana bileşene dahil edilir.

Bileşen 1:

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

Bileşen 2:

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

Kullanmayı denedim @inputve @outputtam olarak nasıl kullanılacağını ve bu işlevi nasıl çağıracağını anlamıyorum, kimse yardımcı olabilir mi?


Yanıtlar:


130

Com1 ve com2 kardeş ise,

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

com2, EventEmitter

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

Burada üst bileşen, myEventolayları dinlemek için bir olay bağlaması ekler ve ardından com1.function1()böyle bir olay gerçekleştiğinde çağrı yapar. #com1bu öğeyi şablonun başka bir yerinden göndermeye izin veren bir şablon değişkenidir. Biz yapmak için kullanırsınız function1()için olay işleyicisi myEventiçinde com2:

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

Bileşenler arasında iletişim kurmak için diğer seçenekler için bkz. Bileşen etkileşimi


Sorunuz ebeveyn-çocuk hakkında hiçbir şey içermiyor. Neyi başarmaya çalışıyorsunuz?
Günter Zöchbauer

"Burada ana bileşen myEvent'i dinlemek için bir olay bağlaması ekler" demeye başladığınızda, kafam çok karıştı. Kardeş bileşen durumunu çözmeye çalıştığımızı sanıyordum. Açısal bağlantı tüm ebeveyn çocuktur, bu yüzden bunları kullanamıyorum.
Angela P

Kardeşlerin ebeveynidir (ev sahibi de diyebilirsiniz). <sibling1 (myEvent)="...">üst / ana makine için bağlayıcı bir olaydır, çünkü Angular bu şekilde sağlar. Ancak olay işleyici, diğer kardeş ( com1) için bir yöntem çağırır . Üst öğe arabulucu olarak kullanılır.
Günter Zöchbauer

Nasıl görünmez denir ?! Sadece içinde somecomponent.tsmi?
Mohammad Kermani

Ancak iki farklı bileşen (Tıklama olayı ((bir bileşen)) listedeki bazı kullanıcılar için ve bu tıklama olayını ayrıntı sayfasındaki (başka bir bileşen)) - Bir Bileşen yönteminden başka bir bileşende kullanmak istiyorum, nasıl yapılır Lütfen söyle bana ??? @ GünterZöchbauer
Jignesh Vagh

164

İlk olarak, bileşenler arasındaki ilişkileri anlamak için gerekenler. O zaman doğru iletişim yöntemini seçebilirsiniz. Bileşenler arasındaki iletişim için pratiğimde bildiğim ve kullandığım tüm yöntemleri açıklamaya çalışacağım.

Bileşenler arasında ne tür ilişkiler olabilir?

1. Ebeveyn> Çocuk

resim açıklamasını buraya girin

Girdi ile Veri Paylaşımı

Bu muhtemelen veri paylaşmanın en yaygın yöntemidir. @Input()Verilerin şablondan geçirilmesine izin vermek için dekoratörü kullanarak çalışır .

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

}

Bu çok basit bir yöntem. Kullanımı kolaydır. Ayrıca ngOnChanges'i kullanarak alt bileşendeki verilerdeki değişiklikleri yakalayabiliriz .

Ancak, bir nesneyi veri olarak kullanırsak ve bu nesnenin parametrelerini değiştirirsek, ona yapılan başvurunun değişmeyeceğini unutmayın. Bu nedenle, bir alt bileşende değiştirilmiş bir nesne almak istiyorsak, değişmez olmalıdır.

2. Çocuk> Ebeveyn

resim açıklamasını buraya girin

ViewChild ile Veri Paylaşma

ViewChild , bir bileşenin diğerine enjekte edilmesine izin vererek ebeveynin özniteliklerine ve işlevlerine erişmesini sağlar. Ancak bir uyarı, childgörünüm başlatılana kadar kullanılamayacak olmasıdır. Bu, alt öğeden veri almak için AfterViewInit yaşam döngüsü kancasını uygulamamız gerektiği anlamına gelir.

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

}

Output () ve EventEmitter ile Veri Paylaşma

Veri paylaşmanın bir başka yolu, çocuk tarafından ebeveyn tarafından listelenebilecek veriler yayınlamaktır. Bu yaklaşım, düğme tıklamaları, form girişleri ve diğer kullanıcı olayları gibi şeylerde meydana gelen veri değişikliklerini paylaşmak istediğinizde idealdir.

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. Kardeşler

resim açıklamasını buraya girin

Çocuk> Ebeveyn> Çocuk

Kardeşler arasında iletişim kurmanın diğer yollarını açıklamaya çalışıyorum. Ancak yukarıdaki yöntemleri anlamanın yollarından birini zaten anlayabilirsiniz.

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

çocuk 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)
  }
}

çocuk 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. İlişkisiz Bileşenler

resim açıklamasını buraya girin

Aşağıda tarif ettiğim tüm yöntemler, bileşenler arasındaki ilişki için yukarıdaki tüm seçenekler için kullanılabilir. Ancak her birinin kendi avantajları ve dezavantajları vardır.

Verileri Hizmetle Paylaşma

Kardeşler, torunlar vb. Gibi doğrudan bağlantısı olmayan bileşenler arasında veri aktarırken, paylaşılan bir hizmet kullanmalısınız. Her zaman senkronize olması gereken veriler olduğunda, bu durumda RxJS BehaviorSubject'i çok yararlı buluyorum.

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")
  }

}

Bir Rota ile Veri Paylaşma

Bazen sadece bileşen arasında basit veri iletmekle kalmaz, aynı zamanda sayfanın bazı durumlarını da kaydedebilirsiniz. Örneğin, çevrimiçi pazarda bir miktar filtre kaydetmek ve ardından bu bağlantıyı kopyalayıp bir arkadaşınıza göndermek istiyoruz. Sayfayı bizimle aynı durumda açmasını bekliyoruz. Bunu yapmanın ilk ve muhtemelen en hızlı yolu sorgu parametrelerini kullanmak olacaktır .

Sorgu parametreleri daha çizgisinde bakmak /people?id=nerede idşey eşit olabilir ve istediğiniz kadar birçok parametre olarak sahip olabilir. Sorgu parametreleri ve işareti karakteriyle ayrılır.

Sorgu parametreleriyle çalışırken, bunları yollar dosyanızda tanımlamanız gerekmez ve bunlara parametreler adı verilebilir. Örneğin, aşağıdaki kodu alın:

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

}

Alıcı sayfada, aşağıdaki gibi bu sorgu parametrelerini alırsınız:

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

Daha karmaşık ancak daha güçlü olan son yol NgRx kullanmaktır . Bu kütüphane veri paylaşımı için değildir; güçlü bir devlet yönetimi kütüphanesidir. Kısa bir örnekte nasıl kullanılacağını açıklayamıyorum, ancak resmi siteye gidip onunla ilgili belgeleri okuyabilirsiniz.

Bana göre NgRx Store birden fazla sorunu çözüyor. Örneğin, gözlemlenebilirlerle ilgilenmeniz gerektiğinde ve gözlemlenebilir bazı verilerin sorumluluğu farklı bileşenler arasında paylaşıldığında, mağaza eylemleri ve redüktör veri değişikliklerinin her zaman "doğru şekilde" yapılmasını sağlar.

Ayrıca HTTP isteklerinin önbelleğe alınması için güvenilir bir çözüm sunar. Yaptığınız isteğin henüz depolanmış bir yanıtı olmadığını doğrulayabilmeniz için istekleri ve yanıtlarını depolayabileceksiniz.

NgRx hakkında okuyabilir ve uygulamanızda buna ihtiyacınız olup olmadığını anlayabilirsiniz:

Son olarak, veri paylaşım yöntemlerinden bazılarını seçmeden önce, bu verilerin gelecekte nasıl kullanılacağını anlamanız gerektiğini söylemek istiyorum. Yani belki şimdi sadece bir @Inputkullanıcı adı ve soyadı paylaşmak için sadece bir dekoratör kullanabilirsiniz . Ardından, kullanıcı hakkında daha fazla bilgi gerektiren yeni bir bileşen veya yeni bir modül (örneğin, bir yönetici paneli) ekleyeceksiniz. Bu, bir hizmeti kullanıcı verileri için kullanmanın daha iyi bir yolu veya veri paylaşmanın başka bir yolu olabileceği anlamına gelir. Veri paylaşımını uygulamaya başlamadan önce daha fazla düşünmeniz gerekir.


3
örnekler ile en iyi açıklama
afeef

1
gördüğüm bu konuya en iyi cevap, tebrikler, ..
Yalnız

Mükemmel açıklama
Moisés Aguilar

htsml'de ts child-two.component.ts görünen adı childMessage olmalıdır (vaka html dosyası kullanıldığında)
Nam Nguyễn

85

Birinci bileşenin yöntemine ikinci bileşenden erişebilirsiniz.

ComponentOne

  ngOnInit() {}

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

componentTwo

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


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


constructor(private comp: oneComponent ) { }

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

componentTwo html dosyası

<button (click)="callMe()">click</button>

2
Örneğin, testCall'i çağırarak componentTwo öğesinden componentOne'da bir değişkene erişmem gerekene kadar benim için buydu.
rey_coder

2
ComponentTwo den testCall çağırırsanız, testCall yönteminin içinde componentOne değişken değerleri almıyorum. Herhangi bir fikir?
Raja

Lütfen bu yöntemi Açısal 7 ile İyonik 4 için açıklayın
Mohammad Ayoub Khan

bu şekilde @Raja'nın da aynı problemi yaşamaya devam etmedi
Kevin Dias

1
THQQQQQQQQQQQ ÇOK ÇOK ADAM
Ashu

33

Bileşen 1 (alt öğe):

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

Bileşen 2 (ebeveyn):

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

  function2(){
    this.component1.function1();
  }
}

Güzel cevap, buraya da bakınız .
Şifre

tamam nasıl html üzerinde function2 çağırmak? i always got this.component1 undefined
cajuuh

<com1 # component1 (click) = "function2 ()"> </
com1

1
ViewChild'i @ açısal / core'dan ve ayrıca Component1'i her yerden içe aktarmanız gerektiğini fark ettiğimde bu benim için çalıştı.
Dallas Caley

1
Bileşen sınıfını genişletmek yerine, @ViewChildbenim için çalışan i uesd . Bu örnek için teşekkürler.
Yash

27

Bileşenleriniz (ebeveyn / çocuk) arasındaki ilişkiye bağlıdır, ancak iletişim bileşenleri oluşturmanın en iyi / genel yolu paylaşılan bir hizmet kullanmaktır.

Daha fazla ayrıntı için bu dokümana bakın:

Bununla birlikte, com1'in com2'ye bir örneğini sağlamak için aşağıdakileri kullanabilirsiniz:

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

Com2'de aşağıdakileri kullanabilirsiniz:

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

  function2(){
    // i want to call function 1 from com1 here
    this.com1ref.function1();
  }
}

hata alıyorum Bilinen bir yerel özellik olmadığından 'com1Ref'
bağlayamıyorum

ve this.com1.function1 () almıyor; bunun yerine this.com1ref.function1 ();
noobProgrammer

Yazım hatası yaptığınız için teşekkürler! Eğer var mı @Inputsahada?
Thierry Templier

Tamam onun çalışma, bana nasıl ebeveyn-çocuk ilişkisi için aynı elde etmek söyleyebilir?
noobProgrammer

1
ebeveyn çocuk için aynı denedim ama undegined function1 () diyor
noobProgrammer

1
  • Diyelim ki 1. bileşen DbstatsMainComponent
  • 2. bileşen DbstatsGraphComponent.
  • 2. yöntem çağrıştıran 1. bileşen

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

#dbgraphÜst bileşenin üst öğenin yöntemlerine erişmek için kullanabileceği yerel değişkeni not edin ( dbgraph.displayTableGraph()).


0

Dataservice kullanarak fonksiyonu başka bir bileşenden çağırabiliriz

Bileşen1: İşlevi çağırdığımız bileşen

constructor( public bookmarkRoot: dataService ) { } 

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

dataservice.ts

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

Bileşen2: İşlevi içeren bileşen

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

 closeDrawer() {
        console.log("this is called")
    }

bu kodu yapıcı içinde kullanmaktan kaçınmak için birkaç kez if ( this.bookmarkRoot.callToggle.observers.length === 0 ) { this.bookmarkRoot.callToggle.subscribe(( data ) => { this.closeDrawer(); } ) }
çağrılabilir
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.