Как вызвать функцию других компонентов в angular2 - программирование
Подтвердить что ты не робот

Как вызвать функцию других компонентов в 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, но я точно не понимаю, как его использовать и как вызывать эту функцию, кто-нибудь может помочь?

4b9b3361

Ответ 1

Если 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() обработчиком событий для myEvent из com2:

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

Другие варианты взаимодействия между компонентами см. также компонент-взаимодействие.

Ответ 2

Во-первых, что вам нужно, чтобы понять отношения между компонентами. Тогда вы можете выбрать правильный способ общения. Я попытаюсь объяснить все методы, которые я знаю и использую в своей практике для взаимодействия между компонентами.

Какие могут быть отношения между компонентами?

1. Родитель> Ребенок

enter image description here

Обмен данными с помощью ввода

Это, наверное, самый распространенный способ обмена данными. Он работает с помощью декоратора @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. Ребенок> Родитель

enter image description here

Обмен данными через ViewChild

ViewChild позволяет одному компоненту внедряться в другой, предоставляя родительскому доступу его атрибуты и функции. Однако одно предостережение заключается в том, что child не будет доступен до тех пор, пока представление не будет инициализировано. Это означает, что нам нужно реализовать хук жизненного цикла 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. Братья, сестры

enter image description here

Ребенок> Родитель> Ребенок

Я пытаюсь объяснить другие способы общения между братьями и сестрами ниже. Но вы уже могли понять один из способов понимания вышеуказанных методов.

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

ребенка 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)
  }
}

ребенка 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. Несвязанные компоненты

enter image description here

Все методы, которые я описал ниже, могут быть использованы для всех вышеупомянутых опций для связи между компонентами. Но у каждого есть свои преимущества и недостатки.

Обмен данными с сервисом

При передаче данных между компонентами, которые не имеют прямого соединения, такими как братья и сестры, внуки и т.д., Вы должны использовать общую службу. Когда у вас есть данные, которые всегда должны быть синхронизированы, я считаю, что 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 и понять, нужно ли вам это в вашем приложении или нет:

Наконец, я хочу сказать, что перед выбором некоторых методов обмена данными вам необходимо понять, как эти данные будут использоваться в будущем. Я имею в виду, может быть, сейчас вы можете использовать только декоратор @Input для совместного использования имени пользователя и фамилии. Затем вы добавите новый компонент или новый модуль (например, панель администратора), который нуждается в дополнительной информации о пользователе. Это означает, что это может быть лучшим способом использования службы для пользовательских данных или каким-либо другим способом обмена данными. Вы должны подумать об этом больше, прежде чем начать осуществлять обмен данными.

Ответ 3

Вы можете получить доступ к компоненту один метод из компонента два..

ComponentOne

  ngOnInit() {}

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

componentTwo

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>

Ответ 4

Компонент 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();
  }
}

Ответ 5

Это зависит от отношений между вашими компонентами (родительский/дочерний), но лучший/универсальный способ создания коммуникационных компонентов - это использование общей службы.

Смотрите этот документ для более подробной информации:

При этом, вы можете использовать следующее для предоставления экземпляра 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();
  }
}

Ответ 6

  • Допустим, 1-й компонент - это DbstatsMainComponent
  • 2-й компонент DbstatsGraphComponent.
  • 1-й компонент, вызывающий метод 2-го

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

Обратите внимание на локальную переменную #dbgraph в дочернем компоненте, которую родитель может использовать для доступа к своим методам (dbgraph.displayTableGraph()).

Ответ 7

Используя Dataservice, мы можем вызвать функцию из другого компонента

Компонент1: компонент, который мы называем функцией

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