我有两个组件如下,我想从另一个组件调用一个函数。这两个组件都包含在第三个父组件using指令中。

组件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,但我不清楚如何使用它以及如何调用该函数,有人能帮忙吗?


当前回答

假设第一个组件是DbstatsMainComponent 第二个组件DbstatsGraphComponent。 第一个组件调用第二个方法

<按钮(点击)= " dbgraph.displayTableGraph ()“图> < / >按钮 < dbstats-graph # dbgraph > < / dbstats-graph >

注意子组件上的局部变量#dbgraph,父组件可以使用它来访问它的方法(dbgraph. displaytablegraph())。

其他回答

我在父组件中使用触发器函数1(子函数),如下所示:

组件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)

首先,您需要了解组件之间的关系。然后你可以选择正确的沟通方式。我将尝试解释我所知道的和在实践中用于组件之间通信的所有方法。

组件之间可以有什么样的关系?

1. 父母>孩子

通过输入共享数据

这可能是共享数据的最常用方法。它通过使用@Input()装饰器来允许数据通过模板传递。

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

}

这是一个非常简单的方法。它很容易使用。我们还可以使用ngOnChanges来捕获子组件中数据的变化。

但是不要忘记,如果我们使用一个对象作为数据,并改变了这个对象的参数,对它的引用将不会改变。因此,如果我们想在子组件中接收一个修改过的对象,它必须是不可变的。

2. 孩子>父母

通过ViewChild共享数据

ViewChild允许将一个组件注入到另一个组件中,使父组件可以访问它的属性和函数。但是需要注意的是,在视图初始化之前,子对象是不可用的。这意味着我们需要实现AfterViewInit生命周期钩子来接收来自子对象的数据。

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()和EventEmitter共享数据

共享数据的另一种方法是从子进程发出数据,这些数据可以由父进程列出。当您希望共享发生在按钮单击、表单条目和其他用户事件上的数据更改时,这种方法是理想的。

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

子>父>子

下面我试着解释兄弟姐妹之间的其他交流方式。但是你已经理解了上面方法的一种理解方式。

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. 不相关的组件

我在下面描述的所有方法都可以用于上述组件之间关系的所有选项。但每一种都有自己的优点和缺点。

与服务共享数据

当在缺少直接连接的组件之间传递数据时,例如兄弟姐妹、孙子姐妹等,您应该使用共享服务。当你的数据应该始终保持同步时,我发现RxJS的BehaviorSubject在这种情况下非常有用。

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

}

通过路由共享数据

有时您不仅需要在组件之间传递简单的数据,还需要保存页面的某些状态。例如,我们想在网上市场保存一些过滤器,然后复制这个链接,发送给一个朋友。我们希望它以和我们相同的状态打开页面。第一种(可能也是最快的)方法是使用查询参数。

查询参数看起来更像是/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。这个库不是用于数据共享的;它是一个功能强大的状态管理库。我不能用一个简短的例子来解释如何使用它,但你可以去官方网站阅读有关它的文档。

对我来说,NgRx Store解决了多个问题。例如,当你必须处理可观察数据时,当一些可观察数据的责任在不同的组件之间共享时,存储操作和减速器确保数据修改总是以“正确的方式”执行。

它还为HTTP请求缓存提供了可靠的解决方案。您将能够存储请求及其响应,以便您可以验证正在发出的请求还没有存储响应。

你可以阅读NgRx,了解你的应用程序是否需要它:

Angular的服务层:Redux、RxJs和Ngrx Store——什么时候使用Store,为什么? Ngrx商店-架构指南

Finally, I want to say that before choosing some of the methods for sharing data you need to understand how this data will be used in the future. I mean maybe just now you can use just an @Input decorator for sharing a username and surname. Then you will add a new component or new module (for example, an admin panel) which needs more information about the user. This means that may be a better way to use a service for user data or some other way to share data. You need to think about it more before you start implementing data sharing.

使用Dataservice,我们可以从另一个组件调用该函数

Component1:我们调用该函数的组件

constructor( public bookmarkRoot: dataService ) { } 

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

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

组件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();
  }
}

假设第一个组件是DbstatsMainComponent 第二个组件DbstatsGraphComponent。 第一个组件调用第二个方法

<按钮(点击)= " dbgraph.displayTableGraph ()“图> < / >按钮 < dbstats-graph # dbgraph > < / dbstats-graph >

注意子组件上的局部变量#dbgraph,父组件可以使用它来访问它的方法(dbgraph. displaytablegraph())。