Angular5-如何调用不同组件的功能

时间:2018-11-15 22:12:16

标签: angular

我有一个带有模板的组件,该模板可以调用其他组件中的函数。

<div class="collapse list-unstyled">
<div *ngFor="let data of data1; let i=index">
 <li>
 <a  class="dropdown-item menu-item"  (click)= menu(i)  >
                                {{data.item}} 
                            </a>
 </li>
 </div>

此处菜单(i)是其他组件的功能。 因此,我想从该组件直接调用另一个组件中的函数。它们在组件之间没有父子关系。对我而言,最好的方法是什么?

2 个答案:

答案 0 :(得分:1)

简短的答案是您不能这样做。每个组件都是一个独立的实体,除非一个组件包含在另一个组件中(父/子关系),否则它们之间没有直接的通信机制。

如果您需要构建一些可由多个组件调用的功能,请构建服务。然后,任何需要它的组件都可以访问该服务。

您甚至可以使用服务共享数据。例如,一个组件可以将一些标志设置到服务中,而另一组件可以稍后从服务中读取那些标志。

如果您认为合适,另一种选择是使用路由器并路由到其他组件。

这是我一段时间后做的图表,用于确定组件之间进行通信的一些关键技术。

enter image description here

答案 1 :(得分:0)

理想情况下,在这种情况下,您不希望像通常提供服务那样提供组件,如当前接受的答案所示。您可以/应该使用共享服务。我将建议一项共享服务,以允许组件之间进行所需的组件通信。

您首先需要的是一项通用服务,任何组件都可以通过IOular容器通过IoC容器注入。看起来可能像这样:

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

@Injectable()
export class CommonService {
    menuChoosen$ = new Subject<number>();

    constructor() { }
}

由于您似乎正在使用Angular 5,因此需要从应用模块中提供此服务。

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppComponent } from './app.component';
import { OneComponent } from './one/one.component';
import { AnotherComponent } from './another/another.component';
import { CommonService } from './common.service';

@NgModule({
imports:      [ BrowserModule, FormsModule ],
declarations: [ AppComponent,
    OneComponent,
    AnotherComponent,
    YetAnotherComponent ],
providers:  [ CommonService ], // HERE
bootstrap:    [ AppComponent ]
})
export class AppModule { }

CommonService服务公开了menuChoosen$ Subject,任何组件都可以在需要知道何时选择菜单项时订阅。在选择了菜单项的组件中,您注入了公共服务,并在选择了菜单选项时在主题上调用next函数。

import { Component, OnInit } from '@angular/core';
import { CommonService } from '../common.service';

@Component({
    selector: 'app-one',
    templateUrl: './one.component.html',
    styleUrls: ['./one.component.css']
})
export class OneComponent implements OnInit {
    data1 = [{item: 'Menu Item 1 (index 0)'}, {item: 'Menu Item 2 (index 1)'}, {item: 'Menu Item 3 (index 2)'}];
    constructor(private commonService: CommonService) { }

    ngOnInit() { }
    menu(index: number) {
        this.commonService.menuChoosen$.next(index); // next fired here!!
    }
}

OneComponent的模板如下所示:

<div *ngFor="let data of data1; let i=index">
    <li (click)="menu(i)">{{data.item}} </li>
</div>

单击列表项(菜单项)后,索引(i)值将发送到menu函数,该函数依次调用CommonService next的{​​{1}}函数主题。

随后,所有其他订阅menuChoosen$主题的组件都会被更新。在这种情况下,menuChoosen$是订户,并且将知道事件。见下文。

AnotherComponent

import { Component, OnInit } from '@angular/core'; import { CommonService } from '../common.service'; @Component({ selector: 'app-another', templateUrl: './another.component.html', styleUrls: ['./another.component.css'] }) export class AnotherComponent implements OnInit { chosenMenuIndex: number; constructor(private commonService: CommonService) { } ngOnInit() { // the subscription starts below this.commonService.menuChoosen$.subscribe(idx => { this.chosenMenuIndex = idx; this.menu(this.chosenMenuIndex); // local function call console.log('menu index chosen: ', this.chosenMenuIndex); }); } menu(index: number) { // do something } } 的模板如下。

AnotherComponent

一旦选择新菜单项,<p> Menu Index: {{chosenMenuIndex}} </p> 值将更新。您可以在订阅中执行应用程序所需的任何操作。

为什么与提供和注入另一个组件相比,共享或通用服务是更好的选择?它可以防止紧密耦合组件。任何给定的组件都不应该对其他组件有任何了解,除非父组件需要了解子组件。

如果您选择像提供服务一样提供组件,并将该组件注入另一个组件,则它们紧密耦合。一个组件完全依赖于另一组件。它可以从一个组件开始,取决于一个其他组件,但是可以迅速变成一个组件,这取决于另一个组件,然后是另一个,然后是另一个。接下来您会知道,当一项服务可以为您解决这些问题时,您将提供大量组件。

这里example stackblitz是使用共享服务进行组件通信。