如何在angular2中调用另一个组件函数

noo*_*mer 130 angular2-components angular

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

第1部分:

@component(
    selector:'com1'
)
export class com1{
    function1(){...}
}
Run Code Online (Sandbox Code Playgroud)

第2部分:

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

我已经尝试使用@input@output,但我不明白究竟是如何使用它,以及如何调用该函数,任何人都可以帮忙吗?

Gün*_*uer 112

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

@component({
  selector:'com1',
})
export class com1{
  function1(){...}
}
Run Code Online (Sandbox Code Playgroud)

com2使用a发出事件 EventEmitter

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

这里父组件添加一个事件绑定来监听myEvent事件,然后com1.function1()在发生这样的事件时调用. #com1是一个模板变量,允许从模板中的其他位置引用此元素.我们用它来使function1()事件处理程序myEventcom2:

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

有关组件之间通信的其他选项,请参阅https://angular.io/docs/ts/latest/cookbook/component-communication.html

  • 亲子沟通怎么样? (2认同)

Rom*_*dan 84

我会尽力回答你的问题.

以前回答的所有人都是对的.首先,您需要了解组件之间的关系.然后你可以选择正确的沟通方式.我试着更多地解释你想要的小甜菜.并解释我所知道并在我的实践中用于组件之间通信的所有方法.

组件之间可以有哪些关系?

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() { }
}
Run Code Online (Sandbox Code Playgroud)

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

}
Run Code Online (Sandbox Code Playgroud)

这是一种非常简单的方法.它很容易使用.我们还可以使用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
  }
}
Run Code Online (Sandbox Code Playgroud)

child.component.ts

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

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

  message = 'Hello!';

  constructor() { }

}
Run Code Online (Sandbox Code Playgroud)

通过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
  }
}
Run Code Online (Sandbox Code Playgroud)

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)
  }
}
Run Code Online (Sandbox Code Playgroud)

兄弟姐妹

在此输入图像描述

孩子>父母>孩子

我试着解释下面兄弟姐妹之间沟通的其他方式.但是你已经可以理解了解上述方法的方法之一.

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
  }
}
Run Code Online (Sandbox Code Playgroud)

儿童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)
  }
}
Run Code Online (Sandbox Code Playgroud)

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

}
Run Code Online (Sandbox Code Playgroud)

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

}
Run Code Online (Sandbox Code Playgroud)

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

}
Run Code Online (Sandbox Code Playgroud)

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

}
Run Code Online (Sandbox Code Playgroud)

与路线共享数据

有时您不仅需要在组件之间传递简单数据,还需要保存页面的某些状态.例如,我们希望在在线市场中保存一些过滤器,然后复制此链接并发送给朋友.我们希望它以与我们相同的状态打开页面.第一种也许是最快捷的方法是使用查询参数.

查询参数看起来更像是child在哪里/people?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);
    }

}
Run Code Online (Sandbox Code Playgroud)

在接收页面中,您将收到以下查询参数:

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

}
Run Code Online (Sandbox Code Playgroud)

NGRX

使用NGRX失去方式,更复杂但更强大.这个库不用于数据共享它是一个功能强大的状态管理库.我不能简单地解释如何使用它,但你可以去官方网站阅读有关它的文档.

对我来说,Ngrx商店解决了多个问题.例如,当您必须处理可观察对象以及在不同组件之间共享某些可观察数据的责任时.在这种情况下,存储操作和缩减器确保始终以"正确的方式"执行数据修改.

它还为HTTP请求缓存提供了可靠的解决方案.您将能够存储请求及其响应,以便您可以验证您正在进行的请求尚未存储响应.

你可以在那里阅读有关ngrx的内容并了解你是否需要在你的应用程序中使用它

最后,我想说在选择一些共享数据的方法之前,您需要了解将来如何使用这些数据.我的意思是也许刚才你可以使用id装饰器来分享用户名和姓氏.然后,您将添加一个新组件或新模块(例如,管理面板),您还需要有关用户的信息.这意味着可能是将服务用于用户数据或其他方式共享数据的更好方式.在开始实现数据共享之前,您需要更多地考虑它.

我希望我的回答对很多人都有用.

  • 最好的例子解释 (9认同)
  • 这篇文章非常好,很简单,谢谢 (3认同)

Jay*_*tha 72

您可以从组件2访问组件的方法.

ComponentOne的

  ngOnInit() {}

  public testCall(){
    alert("I am here..");    
  }
Run Code Online (Sandbox Code Playgroud)

componentTwo

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


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


constructor(private comp: oneComponent ) { }

public callMe(): void {
    this.comp.testCall();
  }
Run Code Online (Sandbox Code Playgroud)

componentTwo html文件

<button (click)="callMe()">click</button>
Run Code Online (Sandbox Code Playgroud)

  • 直到我需要例如通过调用testCall从componentTwo中访问componentOne中的变量的情况下,这才由我完成。 (2认同)
  • 如果我从componentTwo调用testCall,我不会在testCall方法中获取componentOne变量值。任何的想法? (2认同)

Iho*_*iak 28

第1部分(儿童):

@Component(
  selector:'com1'
)
export class Component1{
  function1(){...}
}
Run Code Online (Sandbox Code Playgroud)

组件2(父母):

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

  function2(){
    this.component1.function1();
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 好吧,我如何在 html 上调用 function2 ?我总是得到这个。component1 未定义 (3认同)

Thi*_*ier 26

它取决于组件(父/子)之间的关系,但制作通信组件的最佳/通用方法是使用共享服务.

有关详细信息,请参阅此文档:

话虽这么说,您可以使用以下命令将com1的实例提供给com2:

<div>
  <com1 #com1>...</com1>
  <com2 [com1ref]="com1">...</com2>
</div>
Run Code Online (Sandbox Code Playgroud)

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

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

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


Sha*_*med 5

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

Component1:我们调用函数的组件

constructor( public bookmarkRoot: dataService ) { } 

onClick(){
     this.bookmarkRoot.callToggle.next( true );
}
Run Code Online (Sandbox Code Playgroud)

数据服务.ts

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

Component2:包含该功能的组件

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

 closeDrawer() {
        console.log("this is called")
    }
Run Code Online (Sandbox Code Playgroud)