pasar - recargar componente angular
Cómo llamar a otra función de componentes en angular2 (6)
Tengo dos componentes como sigue y quiero llamar a una función desde otro componente. Ambos componentes se incluyen en el tercer componente principal mediante la directiva.
Componente 1:
@component(
selector:''com1''
)
export class com1{
function1(){...}
}
Componente 2:
@component(
selector:''com2''
)
export class com2{
function2(){...
// i want to call function 1 from com1 here
}
}
He intentado usar
@input
y
@output
pero no entiendo exactamente cómo usarlo y cómo llamar a esa función, ¿alguien puede ayudarme?
Componente 1 (hijo):
@Component(
selector:''com1''
)
export class Component1{
function1(){...}
}
Componente 2 (padre):
@Component(
selector:''com2'',
template: `<com1 #component1></com1>`
)
export class Component2{
@ViewChild("component1") component1: Component1;
function2(){
this.component1.function1();
}
}
Depende de la relación entre sus componentes (padre / hijo), pero la mejor forma genérica de hacer que los componentes de comunicación se comuniquen es usar un servicio compartido.
Vea este documento para más detalles:
Dicho esto, puede usar lo siguiente para proporcionar una instancia de com1 en com2:
<div>
<com1 #com1>...</com1>
<com2 [com1ref]="com1">...</com2>
</div>
En com2, puede usar lo siguiente:
@Component({
selector:''com2''
})
export class com2{
@Input()
com1ref:com1;
function2(){
// i want to call function 1 from com1 here
this.com1ref.function1();
}
}
Primero, lo que necesita para comprender las relaciones entre los componentes. Entonces puede elegir el método de comunicación correcto. Trataré de explicar todos los métodos que conozco y utilizo en mi práctica para la comunicación entre componentes.
¿Qué tipo de relaciones entre componentes puede haber?
1. Padre> Niño
Compartir datos a través de la entrada
Este es probablemente el método más común para compartir datos.
Funciona usando el decorador
@Input()
para permitir que los datos pasen a través de la plantilla.
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() { }
}
Este es un método muy simple. Es fácil de usar. También podemos detectar cambios en los datos en el componente secundario utilizando ngOnChanges .
Pero no olvide que si usamos un objeto como datos y cambiamos los parámetros de este objeto, la referencia a él no cambiará. Por lo tanto, si queremos recibir un objeto modificado en un componente hijo, debe ser inmutable.
2. Niño> Padre
Compartir datos a través de ViewChild
ViewChild
permite que un componente se inyecte en otro, dando al padre acceso a sus atributos y funciones.
Sin embargo, una advertencia es que el
child
no estará disponible hasta después de que se haya inicializado la vista.
Esto significa que necesitamos implementar el enlace del ciclo de vida AfterViewInit para recibir los datos del niño.
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() { }
}
Compartir datos a través de Output () y EventEmitter
Otra forma de compartir datos es emitir datos del elemento secundario, que el padre puede enumerar. Este enfoque es ideal cuando desea compartir los cambios de datos que ocurren en cosas como clics de botones, entradas de formularios y otros eventos de usuario.
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. hermanos
Niño> Padre> Niño
Trato de explicar otras formas de comunicación entre hermanos a continuación. Pero ya podría entender una de las formas de entender los métodos anteriores.
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. Componentes no relacionados
Todos los métodos que he descrito a continuación se pueden usar para todas las opciones anteriores para la relación entre los componentes. Pero cada uno tiene sus propias ventajas y desventajas.
Compartir datos con un servicio
Al pasar datos entre componentes que carecen de una conexión directa, como hermanos, nietos, etc., debe utilizar un servicio compartido. Cuando tiene datos que siempre deben estar sincronizados, encuentro que RxJS BehaviorSubject es muy útil en esta situación.
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")
}
}
Compartir datos con una ruta
A veces, no solo necesita pasar datos simples entre componentes, sino también guardar algún estado de la página. Por ejemplo, queremos guardar un filtro en el mercado en línea y luego copiar este enlace y enviarlo a un amigo. Y esperamos que abra la página en el mismo estado que nosotros. La primera forma, y probablemente la más rápida, de hacerlo sería utilizar parámetros de consulta .
Los parámetros de consulta se ven más en la línea de
/people?id=
donde
id
puede ser igual a cualquier cosa y puede tener tantos parámetros como desee.
Los parámetros de consulta estarían separados por el carácter de comercial.
Cuando trabaje con parámetros de consulta, no necesita definirlos en su archivo de rutas, y pueden denominarse parámetros. Por ejemplo, tome el siguiente código:
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);
}
}
En la página de recepción, recibiría estos parámetros de consulta como los siguientes:
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
La última forma, que es más complicada pero más poderosa, es usar NgRx . Esta biblioteca no es para compartir datos; Es una poderosa biblioteca de gestión de estado. En un breve ejemplo, no puedo explicar cómo usarlo, pero puede ir al sitio oficial y leer la documentación al respecto.
Para mí, NgRx Store resuelve múltiples problemas. Por ejemplo, cuando tiene que tratar con observables y cuando la responsabilidad de algunos datos observables se comparte entre diferentes componentes, las acciones de la tienda y el reductor aseguran que las modificaciones de datos siempre se realizarán "de la manera correcta".
También proporciona una solución confiable para el almacenamiento en caché de solicitudes HTTP. Podrá almacenar las solicitudes y sus respuestas para que pueda verificar que la solicitud que está realizando aún no tiene una respuesta almacenada.
Puede leer sobre NgRx y comprender si lo necesita en su aplicación o no:
- Capas de servicio angular: Redux, RxJs y Ngrx Store: ¿cuándo usar una tienda y por qué?
- Tienda Ngrx - Una guía de arquitectura
Finalmente, quiero decir que antes de elegir algunos de los métodos para compartir datos, debe comprender cómo se utilizarán estos datos en el futuro.
Quiero decir, tal vez ahora puedes usar solo un decorador
@Input
para compartir un nombre de usuario y un apellido.
Luego agregará un nuevo componente o un nuevo módulo (por ejemplo, un panel de administración) que necesita más información sobre el usuario.
Esto significa que puede ser una mejor manera de utilizar un servicio para los datos del usuario o alguna otra forma de compartir datos.
Debe pensarlo más antes de comenzar a implementar el intercambio de datos.
Puede acceder al método del componente uno desde el componente dos.
componente uno
ngOnInit() {}
public testCall(){
alert("I am here..");
}
componente Dos
import { oneComponent } from ''../one.component'';
@Component({
providers:[oneComponent ],
selector: ''app-two'',
templateUrl: ...
}
constructor(private comp: oneComponent ) { }
public callMe(): void {
this.comp.testCall();
}
componente Dos archivos html
<button (click)="callMe()">click</button>
Si com1 y com2 son hermanos, puede usar
@component({
selector:''com1'',
})
export class com1{
function1(){...}
}
com2 emite un evento usando un
EventEmitter
@component({
selector:''com2'',
template: `<button (click)="function2()">click</button>`
)
export class com2{
@Output() myEvent = new EventEmitter();
function2(){...
this.myEvent.emit(null)
}
}
Aquí el componente principal agrega un enlace de evento para escuchar los eventos
myEvent
y luego llama a
com1.function1()
cuando tal evento ocurre.
#com1
es una variable de plantilla que permite hacer referencia a este elemento desde otra parte de la plantilla.
Usamos esto para hacer que
function1()
el controlador de eventos para
myEvent
de
com2
:
@component({
selector:''parent'',
template: `<com1 #com1></com1><com2 (myEvent)="com1.function1()"></com2>`
)
export class com2{
}
Para otras opciones para comunicarse entre componentes, vea también component-interaction
- Digamos que el primer componente es DbstatsMainComponent
- 2do componente DbstatsGraphComponent.
- 1er componente llamando al método del 2do
<button (click)="dbgraph.displayTableGraph()">Graph</button> <dbstats-graph #dbgraph></dbstats-graph>
Tenga en cuenta la variable local
#dbgraph
en el componente secundario, que el padre puede usar para acceder a sus métodos (
dbgraph.displayTableGraph()
).