Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 4 execute function from another component

Tags:

angular

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.

like image 397
celsomtrindade Avatar asked Jul 25 '17 12:07

celsomtrindade


People also ask

How do I call ngOnInit from another component?

The short answer is to use ViewChild to call the function on component B.


2 Answers

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

like image 78
Piyush Patel Avatar answered Oct 15 '22 00:10

Piyush Patel


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

like image 38
user3502488 Avatar answered Oct 15 '22 00:10

user3502488