I'm build a webapp using Angular4 and I'm trying to create a button to call functions on other components.
I was reading other similar questions here, but they have a scenario where the components are child or sibling components with the declaration on the html, e.g.:
<parent-component>
<child-component></child-component>
<sibling-component></sibling-component>
</parent-component>
However, I'm working on a different scenario, because my components are Invoked via routing
and I can't make it work.
Basically I have a header
on the page with some controls to execute functions, but these functions need to trigger/change data on other components loaded via the routing.
For example, I have the routing /store
to show a list of stores, I also have a drawer on this page that I want to show when the user clicks on a button on the header, this is the problem, because I can't propagate the event from the HeaderComponent
to the StoreComponent
.
These are my files:
header.component.ts
@Component({
selector: 'header',
templateUrl: `
<section class="container">
<button (click)="clickFilter()">Open filter</button>
</section>
`
})
export class HeaderComponent {
@Output() onFilter: EventEmitter = new EventEmitter();
clickFilter():void {
this.onFilter.emit('Register click');
}
}
store.component.ts
@Component({
templateUrl: 'store.html'
})
export class StoreComponent {
onFilterClick(event) {
console.log('Fire onFilterClick: ', event);
}
}
// store.html
<article class="card" (onFilter)="onFilterClick($event)">
Test
</article>
But this is not working.
Also, I don't actually need to call a function, I could just pass a boolean value, for example, to bind to a property on the StoreComponent and then toggle the div inside the html file.
The short answer is to use ViewChild to call the function on component B.
I didn't get time to test it but similar solution worked for me. the code created for your need.
Create a service like this
import { Injectable } from '@angular/core'; import { Observable } from 'rxjs/Observable'; import { Subject } from 'rxjs/Subject'; @Injectable() export class MessageService { private _listners = new Subject<any>(); listen(): Observable<any> { return this._listners.asObservable(); } filter(filterBy: string) { this._listners.next(filterBy); } }
then implement in your header component like this
// header.component.ts @Component({ selector: 'header', templateUrl: ` <section class="container"> <button (click)="clickFilter()">Open filter</button> </section> ` }) export class HeaderComponent { @Output() onFilter: EventEmitter = new EventEmitter(); constructor(private _messageService: MessageService){} clickFilter():void { // this.onFilter.emit('Register click'); this._messageService.filter('Register click'); } }
then use in your store component like this
@Component({ selector: 'store', template: `<article class="card"> Test </article>` }) export class StoreComponent { constructor(private _messageService: MessageService){ this._messageService.listen().subscribe((m:any) => { console.log(m); this.onFilterClick(m); }) } onFilterClick(event) { console.log('Fire onFilterClick: ', event); } }
The concept is that you can use observable in a service and subscribe in the component where you want it (store.component) and can send event from anywhere in the app like i did in the header.component
I hope it will help you
I had a similiar situation, but didn´t want to make a service for this. I managed to pass it like callback. It would be something like this:
header.component.ts
@Component({
selector: 'header',
templateUrl: `
<section class="container">
<button (click)="myFunction()">Open filter</button>
</section>
`})
export class HeaderComponent {
@Input() myFunction: Function;
}
Then just to call it passing the function and parameter
// store.html
<header [myFunction]="functionOnStore"></header>
And just declaring functionOnStore normally on store component
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With