Cách gọi hàm thành phần khác trong angular2


154

Tôi có hai thành phần như sau và tôi muốn gọi một chức năng từ một thành phần khác. Cả hai thành phần được bao gồm trong thành phần cha mẹ thứ ba bằng cách sử dụng chỉ thị.

Hợp phần 1:

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

Hợp phần 2:

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

Tôi đã thử sử dụng @input@outputtôi không hiểu chính xác cách sử dụng và cách gọi chức năng đó, có ai có thể giúp đỡ không?


Câu trả lời:


130

Nếu com1 và com2 là anh em ruột, bạn có thể sử dụng

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

com2 phát ra một sự kiện bằng cách sử dụng một EventEmitter

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

Ở đây, thành phần cha mẹ thêm một ràng buộc sự kiện để lắng nghe myEventcác sự kiện và sau đó gọi com1.function1()khi sự kiện đó xảy ra. #com1là một biến mẫu cho phép tham chiếu đến phần tử này từ nơi khác trong mẫu. Chúng tôi sử dụng này để làm cho function1()các xử lý sự kiện cho myEventcác com2:

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

Đối với các tùy chọn khác để giao tiếp giữa các thành phần, xem thêm tương tác thành phần


Câu hỏi của bạn không chứa bất cứ điều gì về cha mẹ-con. Bạn cố gắng để đạt được điều gì?
Günter Zöchbauer

Khi bạn bắt đầu nói "Ở đây, thành phần cha mẹ thêm một ràng buộc sự kiện để nghe myEvent", tôi rất bối rối. Tôi nghĩ rằng chúng tôi đang cố gắng giải quyết tình huống thành phần anh chị em. Liên kết góc là tất cả các phụ huynh, vì vậy tôi không thể sử dụng chúng.
Angela P

Đó là cha mẹ của anh chị em (bạn cũng có thể nói chủ nhà). <sibling1 (myEvent)="...">là một ràng buộc sự kiện cho phụ huynh / máy chủ, bởi vì đó là cách duy nhất mà Angular cung cấp. Tuy nhiên, bộ xử lý sự kiện gọi một phương thức trên anh chị em khác ( com1). Cha mẹ được sử dụng như một trung gian hòa giải.
Günter Zöchbauer

Làm thế nào để gọi nó ra khỏi tầm nhìn?! Chỉ bên trong somecomponent.ts?
Mohammad Kermani

Nhưng nếu hai thành phần khác nhau (sự kiện On Click ((một thành phần)) cho một số người dùng trong danh sách & sao chép sự kiện nhấp đó trên trang chi tiết (thành phần khác)) - Từ phương thức Một thành phần tôi muốn sử dụng trong thành phần khác, làm thế nào để làm điều đó Xin vui lòng cho tôi biết ??? @ GünterZöchbauer
Jignesh Vagh

164

Đầu tiên, những gì bạn cần để hiểu mối quan hệ giữa các thành phần. Sau đó, bạn có thể chọn phương pháp giao tiếp phù hợp. Tôi sẽ cố gắng giải thích tất cả các phương pháp mà tôi biết và sử dụng trong thực tế để giao tiếp giữa các thành phần.

Những loại mối quan hệ giữa các thành phần có thể có?

1. Cha mẹ> Con

nhập mô tả hình ảnh ở đây

Chia sẻ dữ liệu qua đầu vào

Đây có lẽ là phương pháp chia sẻ dữ liệu phổ biến nhất. Nó hoạt động bằng cách sử dụng trình @Input()trang trí để cho phép dữ liệu được truyền qua mẫu.

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

}

Đây là một phương pháp rất đơn giản. Nó rất dễ dàng để sử dụng. Chúng tôi cũng có thể bắt các thay đổi đối với dữ liệu trong thành phần con bằng ngOnChanges .

Nhưng đừng quên rằng nếu chúng ta sử dụng một đối tượng làm dữ liệu và thay đổi các tham số của đối tượng này, thì tham chiếu đến nó sẽ không thay đổi. Do đó, nếu chúng ta muốn nhận một đối tượng đã sửa đổi trong một thành phần con, thì nó phải là bất biến.

2. Con> Cha mẹ

nhập mô tả hình ảnh ở đây

Chia sẻ dữ liệu qua ViewChild

ViewChild cho phép một thành phần được đưa vào một thành phần khác, cho phép cha mẹ truy cập vào các thuộc tính và chức năng của nó. Tuy nhiên, một cảnh báo là childsẽ không khả dụng cho đến khi chế độ xem được khởi tạo. Điều này có nghĩa là chúng ta cần triển khai móc vòng đời AfterViewInit để nhận dữ liệu từ đứa trẻ.

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

}

Chia sẻ dữ liệu qua đầu ra () và EventEuctor

Một cách khác để chia sẻ dữ liệu là phát ra dữ liệu từ trẻ, có thể được liệt kê bởi cha mẹ. Cách tiếp cận này lý tưởng khi bạn muốn chia sẻ các thay đổi dữ liệu xảy ra trên những thứ như nhấp vào nút, mục nhập biểu mẫu và các sự kiện người dùng khác.

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. Anh chị em

nhập mô tả hình ảnh ở đây

Con> Cha mẹ> Con

Tôi cố gắng giải thích những cách khác để giao tiếp giữa anh chị em dưới đây. Nhưng bạn đã có thể hiểu một trong những cách hiểu về các phương pháp trên.

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

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

con-hai.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. Thành phần không liên quan

nhập mô tả hình ảnh ở đây

Tất cả các phương pháp mà tôi đã mô tả dưới đây có thể được sử dụng cho tất cả các tùy chọn ở trên cho mối quan hệ giữa các thành phần. Nhưng mỗi cái đều có ưu điểm và nhược điểm riêng.

Chia sẻ dữ liệu với dịch vụ

Khi truyền dữ liệu giữa các thành phần thiếu kết nối trực tiếp, chẳng hạn như anh chị em, cháu, v.v., bạn nên sử dụng một dịch vụ chia sẻ. Khi bạn có dữ liệu phải luôn đồng bộ, tôi thấy RxJS BehaviorSubject rất hữu ích trong tình huống này.

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

}

Chia sẻ dữ liệu với lộ trình

Đôi khi bạn không chỉ cần chuyển dữ liệu đơn giản giữa các thành phần mà còn lưu một số trạng thái của trang. Ví dụ: chúng tôi muốn lưu một số bộ lọc trong thị trường trực tuyến và sau đó sao chép liên kết này và gửi cho bạn bè. Và chúng tôi hy vọng nó sẽ mở trang ở trạng thái giống như chúng tôi. Cách đầu tiên và có lẽ là nhanh nhất để làm điều này là sử dụng các tham số truy vấn .

Tham số truy vấn tìm kiếm hơn dọc theo dòng của /people?id=nơi idcó thể bằng bất cứ điều gì và bạn có thể có nhiều thông số như bạn muốn. Các tham số truy vấn sẽ được phân tách bằng ký tự dấu và.

Khi làm việc với các tham số truy vấn, bạn không cần xác định chúng trong tệp tuyến đường của mình và chúng có thể được đặt tên là tham số. Ví dụ: lấy mã sau:

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

}

Trong trang nhận, bạn sẽ nhận được các tham số truy vấn như sau:

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

Cách cuối cùng, phức tạp hơn nhưng mạnh hơn, là sử dụng NgRx . Thư viện này không phải để chia sẻ dữ liệu; nó là một thư viện quản lý nhà nước mạnh mẽ Tôi không thể trong một ví dụ ngắn giải thích cách sử dụng nó, nhưng bạn có thể truy cập trang web chính thức và đọc tài liệu về nó.

Đối với tôi, NgRx Store giải quyết nhiều vấn đề. Ví dụ: khi bạn phải xử lý các vật quan sát và khi trách nhiệm đối với một số dữ liệu quan sát được chia sẻ giữa các thành phần khác nhau, các hành động lưu trữ và bộ giảm tốc đảm bảo rằng việc sửa đổi dữ liệu sẽ luôn được thực hiện "đúng cách".

Nó cũng cung cấp một giải pháp đáng tin cậy cho bộ nhớ đệm yêu cầu HTTP. Bạn sẽ có thể lưu trữ các yêu cầu và phản hồi của họ để bạn có thể xác minh rằng yêu cầu bạn đang thực hiện chưa có phản hồi được lưu trữ.

Bạn có thể đọc về NgRx và hiểu xem bạn có cần nó trong ứng dụng của mình hay không:

Cuối cùng, tôi muốn nói rằng trước khi chọn một số phương pháp chia sẻ dữ liệu, bạn cần hiểu cách sử dụng dữ liệu này trong tương lai. Ý tôi là có lẽ bây giờ bạn chỉ có thể sử dụng một @Inputtrang trí để chia sẻ tên người dùng và họ. Sau đó, bạn sẽ thêm một thành phần mới hoặc mô-đun mới (ví dụ: bảng quản trị) cần thêm thông tin về người dùng. Điều này có nghĩa là có thể là một cách tốt hơn để sử dụng dịch vụ cho dữ liệu người dùng hoặc một số cách khác để chia sẻ dữ liệu. Bạn cần suy nghĩ về nó nhiều hơn trước khi bắt đầu thực hiện chia sẻ dữ liệu.


3
giải thích tốt nhất với các ví dụ
afeef

1
câu trả lời hay nhất cho chủ đề này mà tôi từng thấy, xin chúc mừng, ..
Cô đơn

Giải thích rõ ràng
Moisés Aguilar

trong 3. Anh chị em tên ts-hai.component.ts hiển thị trong html phải là childMessage (đối với trường hợp sử dụng tệp html)
Nam Nguyễn

84

Bạn có thể truy cập phương thức của thành phần từ thành phần hai ..

thành phần

  ngOnInit() {}

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

thành phần

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


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


constructor(private comp: oneComponent ) { }

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

thành phần tập tin html

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

2
Đây là nó cho tôi cho đến khi tôi cần truy cập một biến trong thành phầnOne từ thành phần bằng cách gọi testCall .... trường hợp mà giá trị biến được đặt bởi thành phầnOne nhưng thành phần sẽ nhận được mặc định và không phải là hiện tại.
rey_coder

2
Tôi không nhận được các giá trị biến thành phần trong một phương thức testCall nếu tôi gọi testCall từ componentTwo. Bất kỳ ý tưởng?
Raja

Vui lòng giải thích phương pháp này cho Ionic 4 với Angular 7
Mohammad Ayoub Khan

với cách này, nó không khiến cho @Raja gặp vấn đề tương tự
Kevin Dias

1
THQQQQQQQQQQQ RẤT NHIỀU MAN
Ashu

33

Hợp phần 1 (con):

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

Hợp phần 2 (cha mẹ):

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

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

Câu trả lời tốt, xem thêm ở đây .
Mật mã

Được rồi, làm thế nào tôi gọi hàm2 trên html? tôi luôn có cái này.component1 không xác định
cajuuh

<com1 # thành
phần1

1
Điều này làm việc cho tôi, một khi tôi nhận ra rằng bạn phải nhập ViewChild từ @ angular / core và cả Element1 từ bất cứ đâu.
Dallas Caley

1
Thay vì mở rộng lớp thành phần, tôi uesd @ViewChildđã làm việc cho tôi. Cảm ơn ví dụ này.
Yash

27

Nó phụ thuộc vào mối quan hệ giữa các thành phần của bạn (cha mẹ / con cái) nhưng cách tốt nhất / chung để tạo các thành phần giao tiếp là sử dụng dịch vụ chia sẻ.

Xem tài liệu này để biết thêm chi tiết:

Điều đó đang được nói, bạn có thể sử dụng như sau để cung cấp một thể hiện của com1 vào com2:

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

Trong com2, bạn có thể sử dụng như sau:

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

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

tôi đang gặp lỗi Không thể liên kết với 'com1Ref' vì đây không phải là tài sản riêng được biết đến
noobProgrammer

và nó không lấy this.com1.feft1 (); thay vào đó.com1ref.feft1 ();
noobProgrammer

Cảm ơn đã chỉ ra lỗi đánh máy! Bạn có @Inputtrên sân không?
Thierry Templier

ok nó hoạt động, bạn có thể cho tôi biết làm thế nào để đạt được tương tự cho mối quan hệ cha mẹ và con cái ??
noobProgrammer

1
tôi đã cố gắng tương tự cho con của cha mẹ nhưng nó nói hàm1 () của không xác định
noobProgrammer

1
  • Hãy nói rằng thành phần đầu tiên là DbstatsMainComponent
  • Thành phần thứ 2 DbstatsGraphComponent.
  • Thành phần thứ 1 gọi phương thức thứ 2

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

Lưu ý biến cục bộ #dbgraphtrên thành phần con mà cha mẹ có thể sử dụng để truy cập các phương thức của nó ( dbgraph.displayTableGraph()).


0

Sử dụng Dataservice chúng ta có thể gọi hàm từ một thành phần khác

Thành phần 1: Thành phần mà chúng ta đang gọi hàm

constructor( public bookmarkRoot: dataService ) { } 

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

dịch vụ dữ liệu.ts

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

Thành phần 2: Thành phần có chứa hàm

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

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

điều này có thể gọi nhiều lần để tránh việc sử dụng mã này bên trong hàm tạoif ( this.bookmarkRoot.callToggle.observers.length === 0 ) { this.bookmarkRoot.callToggle.subscribe(( data ) => { this.closeDrawer(); } ) }
Shafeeq Mohammed
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.