8

I'm trying to execute a function from another component (These 2 components are NOT siblings). My guess is that I will need to use @Output and eventEmitter to accomplish this or create a Service and subscribe to the Observable to share the same data throughout all the components (I know how to pass a message( string) but I don't know how to execute a function). I'm not really sure where to start. I'm trying to execute function1 FROM function2. Can anyone help me on how to get this to work? Please provide a plunker. This is what my project looks like:

   src
   |__app(FOLDER)
      |__home(FOLDER)
      |     |
      |     |__home.component.ts 
      |                  |______function2(){
      |                          What do I need to put in here to execute function1?
      |                          }
      | 
      |__products(FOLDER) 
           |
           |__tools(FOLDER)
                  |
                  |____tools.component.ts
                                   |____function1(){
                                         alert("I'm inside function 1!!");
                                         }

As you saw I have a file home.component.ts that has function2 and a file tools.component.ts that has function1, so any ideas how to execute function1 from function2 ?

HenryDev
  • 4,685
  • 5
  • 27
  • 64
  • You are correct, you need to emit an event from function 2 which is listened to in `tools.component` and then invokes function 1. The other option which you could try is having a shared service between the components which hosts an observable. Subscribe to the observable and then on update from function 2, run function 1. – Zze Jan 03 '18 at 00:35
  • @Zze can you share your ideas as a solution? Thank you! – HenryDev Jan 03 '18 at 00:36
  • Have a squiz at this and then let me know if it's still unclear. It's not 100% what you need but I will be using a similar event in an answer here. (I don't have time to whip up a full answer right now)... https://stackoverflow.com/questions/38222475/event-delegation-in-angular2/47812255#47812255 – Zze Jan 03 '18 at 00:46
  • Use a shared service – Jota.Toledo Jan 03 '18 at 01:11
  • @Jota.Toledo can you provide an example? Thanks! – HenryDev Jan 03 '18 at 01:19
  • https://angular.io/guide/component-interaction#component-interaction – Jota.Toledo Jan 03 '18 at 01:20
  • 1
    if there is no parent-child relation between your components, the service has to be provided on a high level module – Jota.Toledo Jan 03 '18 at 01:21
  • Does your tools component appear in your home component? – Uğur Dinç Jan 03 '18 at 04:08
  • @Jota.Toledo how to implement the service to execute the function? – HenryDev Jan 03 '18 at 06:24
  • @dexter not it doesnt – HenryDev Jan 03 '18 at 06:25
  • @HenryDev take a look to the link that I provided – Jota.Toledo Jan 03 '18 at 10:13
  • I review this question again and I'd say that yes, you need to emit an event from `function2()` and code a listener inside to `function1()` for executing it when function1 dispatch the event. I think that is a better solution than using a service with an `observable`. – Kenry Sanchez Jan 03 '18 at 14:23
  • @KenrySanchez, yup I know how to do it if they are ot sibling components? – HenryDev Jan 03 '18 at 15:24
  • No. I've never tried before. But, I know you can emit an event from a component with `EventEmitter`. https://angular.io/api/core/EventEmitter – Kenry Sanchez Jan 03 '18 at 16:39
  • same question [here](https://stackoverflow.com/questions/44414226/angular-4-pass-data-between-2-not-related-components) with explained response. – User.Anonymous Jan 20 '18 at 14:15
  • string or callback is same way. – User.Anonymous Jan 22 '18 at 13:52

4 Answers4

6

I agree that your idea regarding a service with an observable is your best option here (as others have suggested) - although I'd prefer a BehaviorSubject in this case. Here's a simple, working plunkr demonstrating how you could implement this:

https://plnkr.co/edit/quHc2yOkxXIbXYUlnZbB?p=preview

If we break down the requirement, what you need here is an Event Proxy service that just passes on the event. This plunkr is also able to also pass a parameter object via the service - in case you need to do this - but if not then just pass any object you want (or just remove the param arguments from all the methods entirely).

This implementation doesnt care that the components are not siblings - because we're using a service. Both will be provided with the same service instance regardless of the structure of your app.

For quick reference, here are the pieces of code that matter:

EventProxyService

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';

@Injectable()
export class EventProxyService {

 private eventSubject = new BehaviorSubject<any>(undefined);

 triggerSomeEvent(param: any) {
     this.eventSubject.next(param);
 }

 getEventSubject(): BehaviorSubject<any> {
    return this.eventSubject;
 }
}

FirstComponent

import { Component, OnInit } from '@angular/core';
import { EventProxyService } from './event-proxy.service';

@Component({
  selector: 'app-first',
  templateUrl: './src/first.component.html'
})
export class FirstComponent implements OnInit {
  displayText = 'I havent created any events yet.';
  constructor(private eventProxyService: EventProxyService) { }

  ngOnInit() { }

  triggerAnEvent() {
    this.eventProxyService.triggerSomeEvent(Date());
    this.displayText = 'I fired an event.'
  }
}

SecondComponent

import { Component, OnInit } from '@angular/core';
import { EventProxyService } from './event-proxy.service';

@Component({
  selector: 'app-second',
  templateUrl: './src/second.component.html'
})
export class SecondComponent implements OnInit {

  displayText = 'I havent got an event yet';
  constructor(private eventProxyService: EventProxyService) { }

  ngOnInit() {
    this.eventProxyService.getEventSubject().subscribe((param: any) => {
      if (param !== undefined) {
        this.theTargetMethod(param);
      }
      });
  }

  theTargetMethod(param) {
    this.displayText = 'Target Method got called with parameter: "' + param + '"';
  }
}
Steve Land
  • 4,852
  • 2
  • 17
  • 36
1

Use a service. Subscribe to a Observable of the service in your home.component and execute a change in the observable from tools

//Your service
private dataSource = new Subject<any>();
data = this.searchDataSource.asObservable();
change(param:any) {
   this.searchDataSource.next(param)
}
//Your home.component
this.myService.data.subscribe((param: any) => {
      console.log(param)
}
//Your tool
this.myService.change("Hello world");

As the question is execute a function, you can use this idea, doing some like

//Your tool:
    this.myService.change("Command1") 
//or even
    this.myService.change({"command":"Command1","arg":myvariable})

//Your home.component
this.myService.data.subscribe((param:any)=>
{  switch (param.command)
   {
      case "Command1":
          this.function1(param.arg);
          break;
      case "Command2":
          this.function2();
          break;
      ....
   }
}
Eliseo
  • 50,109
  • 4
  • 29
  • 67
  • @HenryDev I've updated my answer. I know that it's a work-around but it's the only I can imagine – Eliseo Jan 20 '18 at 20:44
1

Depending on what you are trying to do, you have two options.

First: If you need Angular features (e.g. dependency injection) or want to share data, you should think about using a service. There is enough of documentation and tutorials already (see angular docs.) I recommend reading this thoroughly.

Second: In case you just need JavaScript capabilities, you could create a TypeScript file (e.g. /src/app/shared/tools.ts and put your method there. This is mostly useful for static functions that do some kind of calculations, formatting or similar. You can then import and use the function wherever you need it. (Tip: make it pure.)

Benedikt
  • 954
  • 3
  • 14
  • 25
-1

Inheritance the components.

Let's say one component.

@Component({
...
})
export class Component1 {
  constructor();

  public test1() {
    console.log("this is a test");
  }
}

you can inheritance the first component as a child an execute the test1 method

@Component({
...
})

export Class Component2 extends Component1 {
  constructor();

  //Execute test1 method
  test1();
}

Also, remember that if you are using angular you need to export your components in the declarations and entryComponents. Also you need to import it in your new component.

import { Component1 } from 'directory/component';

/* Example */

import { SplashScreen } from 'directory/splash-screen';

Kenry Sanchez
  • 1,703
  • 2
  • 18
  • 24