簡體   English   中英

"如何在angular2中調用另一個組件函數"

[英]How to call another components function in angular2

我有如下兩個組件,我想從另一個組件調用一個函數。 兩個組件都包含在使用指令的第三個父組件中。

組件 1:

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

組件 2:

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

我試過使用@input@output ,但我不明白如何使用它以及如何調用該函數,有人可以幫忙嗎?

首先,您需要了解組件之間的關系。 然后你可以選擇正確的溝通方式。 我將嘗試解釋我在實踐中知道和使用的所有組件之間通信的方法。

組件之間可以有什么樣的關系?

1. 父 > 子

在此處輸入圖片說明

通過輸入共享數據

這可能是最常見的數據共享方法。 它通過使用@Input()裝飾器來允許數據通過模板傳遞。

父組件.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() { }
}

子組件.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() { }

}

這是一個非常簡單的方法。 這個用起來很簡單。 我們還可以使用ngOnChanges捕獲子組件中數據的更改。

但是不要忘記,如果我們將一個對象用作數據並更改該對象的參數,則對它的引用不會改變。 因此,如果我們想在子組件中接收一個修改過的對象,它必須是不可變的。

2. 子 > 父

在此處輸入圖片說明

通過 ViewChild 共享數據

ViewChild允許將一個組件注入到另一個組件中,從而使父組件可以訪問其屬性和功能。 但是,需要注意的是,在視圖初始化之后, child才可用。 這意味着我們需要實現 AfterViewInit 生命周期鈎子來接收來自孩子的數據。

父組件.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
  }
}

子組件.ts

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

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

  message = 'Hello!';

  constructor() { }

}

通過 Output() 和 EventEmitter 共享數據

共享數據的另一種方法是從子節點發出數據,這些數據可以由父節點列出。 當您想要共享發生在按鈕單擊、表單條目和其他用戶事件等事件上的數據更改時,此方法是理想的選擇。

父組件.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
  }
}

子組件.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. 兄弟姐妹

在此處輸入圖片說明

子 > 父 > 子

我嘗試在下面解釋兄弟姐妹之間交流的其他方式。 但是你已經可以理解其中一種理解上述方法的方法了。

父組件.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. 不相關的組件

在此處輸入圖片說明

我在下面描述的所有方法都可以用於組件之間關系的所有上述選項。 但每個人都有自己的優點和缺點。

與服務共享數據

在缺乏直接連接的組件(例如兄弟、孫子等)之間傳遞數據時,您應該使用共享服務。 當您的數據應該始終保持同步時,我發現 RxJS BehaviorSubject 在這種情況下非常有用。

數據服務.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)
  }

}

第二個組件.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")
  }

}

與路由共享數據

有時您不僅需要在組件之間傳遞簡單的數據,還需要保存頁面的某些狀態。 例如,我們想在網上市場保存一些過濾器,然后復制此鏈接並發送給朋友。 我們希望它以與我們相同的狀態打開頁面。 第一種,可能也是最快的方法是使用查詢參數

查詢參數看起來更像/people?id= ,其中id可以等於任何東西,並且您可以擁有任意數量的參數。 查詢參數將由與字符分隔。

使用查詢參數時,您不需要在路由文件中定義它們,它們可以被命名為參數。 例如,采用以下代碼:

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

}

在接收頁面中,您將收到這些查詢參數,如下所示:

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 本庫不用於數據共享; 它是一個強大的狀態管理庫。 我不能在一個簡短的例子中解釋如何使用它,但你可以去官方網站並閱讀有關它的文檔。

對我來說,NgRx Store 解決了多個問題。 例如,當您必須處理 observable 並且在不同組件之間共享某些 observable 數據的責任時,存儲操作和化簡器確保數據修改始終以“正確的方式”執行。

它還為 HTTP 請求緩存提供了可靠的解決方案。 您將能夠存儲請求及其響應,以便您可以驗證您發出的請求尚未存儲響應。

您可以閱讀 NgRx 並了解您的應用是否需要它:

最后,我想說,在選擇一些共享數據的方法之前,您需要了解這些數據將來將如何使用。 我的意思是也許現在你可以只使用@Input裝飾器來共享用戶名和姓氏。 然后,您將添加需要更多用戶信息的新組件或新模塊(例如,管理面板)。 這意味着將服務用於用戶數據或以其他方式共享數據可能是一種更好的方式。 在開始實施數據共享之前,您需要更多地考慮它。

如果 com1 和 com2 是兄弟姐妹,您可以使用

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

這里父組件添加了一個事件綁定來監聽myEvent事件,然后在發生此類事件時調用com1.function1() #com1是一個模板變量,允許從模板的其他地方引用這個元素。 我們使用它使function1()成為com2 myEvent的事件處理程序:

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

有關組件之間通信的其他選項,另請參閱組件交互

您可以從組件二訪問組件一的方法。

組件一

  ngOnInit() {}

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

組件二

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


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


constructor(private comp: oneComponent ) { }

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

componentTwo html 文件

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

組件 1(子項):

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

組件 2(父):

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

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

這取決於您的組件(父/子)之間的關系,但制作通信組件的最佳/通用方法是使用共享服務。

有關更多詳細信息,請參閱此文檔:

話雖如此,您可以使用以下內容將 com1 的實例提供給 com2:

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

在 com2 中,您可以使用以下內容:

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

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

使用 Dataservice 我們可以從另一個組件調用該函數

Component1:我們調用函數的組件

constructor( public bookmarkRoot: dataService ) { } 

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

數據服務.ts

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

Component2:包含函數的組件

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

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

在現實世界中,場景不是調用簡單的函數,而是調用具有適當值的函數。 所以讓我們深入研究。這是一個場景 用戶需要從他自己的組件中觸發一個事件,並且最后他還想調用另一個組件的函數。 假設兩個組件的服務文件相同

組件一.html

    <button (click)="savePreviousWorkDetail()" data-dismiss="modal" class="btn submit-but" type="button">
          Submit
        </button>

當用戶點擊提交按鈕時,他需要在自己的組件 componentOne.ts 中調用 savePreviousWorkDetail() ,最后他還需要調用另一個組件的函數。 因此,要做到這一點,可以從 componentOne.ts 調用服務類中的函數,當調用該函數時,將觸發 componentTwo 中的函數。

componentOne.ts

constructor(private httpservice: CommonServiceClass) {
  }

savePreviousWorkDetail() {
// Things to be Executed in this function

this.httpservice.callMyMethod("Niroshan");
}

公共服務類.ts

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

@Injectable()
export class CommonServiceClass{

  invokeMyMethod = new EventEmitter();

  constructor(private http: HttpClient) {
  }

  callMyMethod(params: any = 'Niroshan') {
    this.invokeMyMethod.emit(params);
  }

}

下面是 componentTwo,它具有需要從 componentOne 調用的函數。 在 ngOnInit() 中我們必須訂閱被調用的方法,所以當它觸發 methodToBeCalled() 時將被調用

componentTwo.ts

import {Observable,Subscription} from 'rxjs';


export class ComponentTwo implements OnInit {

 constructor(private httpservice: CommonServiceClass) {
  }

myMethodSubs: Subscription;

ngOnInit() {
    
    this.myMethodSubs = this.httpservice.invokeMyMethod.subscribe(res => {
      console.log(res);
      this.methodToBeCalled();
    });
    
methodToBeCalled(){
//what needs to done
}
  }

}
  • 假設第一個組件是 DbstatsMainComponent
  • 第二個組件 DbstatsGraphComponent。
  • 第一個組件調用第二個方法

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

請注意子組件上的局部變量#dbgraph ,父組件可以使用它來訪問其方法 ( dbgraph.displayTableGraph() )。

  1. 將可注入裝飾器添加到 component2(或任何具有該方法的組件)
@Injectable({
    providedIn: 'root'
})
  1. 注入到 component1(將調用 component2 方法的組件)
constructor(public comp2 : component2) { }
  1. 在 component1 中定義方法,從那里調用 component2 方法
method1()
{
    this.comp2.method2();
}

下面的組件 1 和組件 2 代碼。

import {Component2} from './Component2';

@Component({
  selector: 'sel-comp1',
  templateUrl: './comp1.html',
  styleUrls: ['./comp1.scss']
})
export class Component1 implements OnInit {
  show = false;
  constructor(public comp2: Component2) { }
method1()
 {
   this.comp2.method2(); 
  }
}


@Component({
  selector: 'sel-comp2',
  templateUrl: './comp2.html',
  styleUrls: ['./comp2.scss']
})
export class Component2 implements OnInit {
  method2()
{
  alert('called comp2 method from comp1');
}

我在這樣的父組件中使用 trigger fuction1(子函數):)

組件 1(子項):

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

組件 2(父):

@Component(
  selector:'com2',
  template: `<button (click)="component1.function1()"
             <com1 #component1></com1>`
)
export class Component2{
}

#component1 是模板變量。 您可以將其替換為任何名稱。 (例如:#hello1)

對於不相關的組件,使用共享服務的這種簡單方法。

//你的服務

private subject = new Subject<any>();
sendClickEvent() {
  this.subject.next();
}
getClickEvent(): Observable<any>{ 
  return this.subject.asObservable();
}
}

//你有按鈕的組件

clickMe(){
this.YourServiceObj.sendClickEvent();
}

<button (click)="clickMe()">Click Me</button>

//您收到點擊事件的組件

this.sharedService.getClickEvent().subscribe(()=>{
this.doWhateverYouWant();
}

)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM