31

I want to create service, which can interact with one component. All another components in my app, should be able to call this service, and this service should interact with this component.

How to call component method from service?

@Component({
  selector:'component'
})
export class Component{

  function2(){ 
    // How call it?
  }
}

From this servive?

@Injectable()

export class Service {


  callComponentsMethod() {
    //From this place?;
      }
}
John Doe
  • 3,794
  • 9
  • 40
  • 72

3 Answers3

35

Interaction between components can be indeed achieved using services. You will need to inject the service use for inter-component communication into all the components which will need to use it (all the caller components and the callee method) and make use of the properties of Observables.

The shared service can look something like this:

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

@Injectable()
export class CommunicationService {

  // Observable string sources
  private componentMethodCallSource = new Subject<any>();
  
  // Observable string streams
  componentMethodCalled$ = this.componentMethodCallSource.asObservable();

  // Service message commands
  callComponentMethod() {
    this.componentMethodCallSource.next();
  }
}

Example:

Sender:

callMethod = function () {
   this.communicationService.callComponentMethod();
}

Receiver:

this.communicationService.componentMethodCalled$.subscribe(() => {
      alert('(Component2) Method called!');
});

I have created a basic example here, where clicking on a button from Component1 will call a method from Component2.

If you want to read more on the subject, please refer to the dedicated documentation section: https://angular.io/guide/component-interaction#parent-and-children-communicate-via-a-service

Tudor Ciotlos
  • 1,805
  • 4
  • 29
  • 47
  • It calls callComponentMethod, but does not call componentMethodCallSource. Have you any idea why? – John Doe Nov 24 '16 at 15:41
  • I don't really understand your question. The end result is that Component1 calls a method from Component2. Isn't that what you need? – Tudor Ciotlos Nov 24 '16 at 15:44
  • I do not understand why, but does not calls needed function. – John Doe Nov 24 '16 at 15:47
  • You mean in your application, right? Can you please look in the console to see if there are any errors? – Tudor Ciotlos Nov 24 '16 at 15:49
  • No. There are no errors. I see console.logs only in callComponentMethod, but it does not call needed method. – John Doe Nov 24 '16 at 15:58
  • Make sure you register the shared service as a provider in the root module. If that's not the issue, please show me the code of your application so I can take a look. – Tudor Ciotlos Nov 24 '16 at 16:02
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/128966/discussion-between-max-karpovets-and-tudor-ciotlos). – John Doe Nov 24 '16 at 16:20
  • Could it call component from another module? – John Doe Nov 24 '16 at 19:19
  • I only tested the situation where the components reside in the same module, I don't think it works with different modules. – Tudor Ciotlos Nov 24 '16 at 19:36
  • @Tudor Ciotlos, Your above solution is really good. How to pass value from component 1 to component 2 in method parameter? – Anil Jagtap Apr 12 '17 at 15:21
  • @AnilJagtap Please take a look at this example: https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#bidirectional-service – Tudor Ciotlos Apr 13 '17 at 05:58
  • @TudorCiotlos can you elucidate me on how can I call a component "method" from a service method? Not from another component. I'm using a same dropdown in various components so a I need every component to implement its own version of the service method thats its called when the an option is selected. – Rafael de Castro Jan 07 '18 at 21:56
  • I tested what Tudor Ciotlos explained and it only works if all components are in the same module. If you want to work with this solution and separated modules, you'll need to make adaptions. –  Nov 28 '18 at 12:03
  • the more oftener i call this function it gets fired twice or more. For every time i call it, the next time it is +1. So if i used the function 10 times it gets called 11 times the next time. – Sithys Jan 16 '21 at 12:33
  • @Sithys without seeing your code, my best bet is that you have a RxJs memory leak problem. This article might help: https://netbasal.com/why-its-important-to-unsubscribe-from-rxjs-subscription-a7a6455d6a02 – Tudor Ciotlos Jan 17 '21 at 19:08
20

The question does not ask component interaction, it asks for calling a component method from a service.

This simply can be achieved by injecting service to the component. Then define a method inside the service which takes a function as parameter. The method should save this function as a property of service and call it wherever it wants.

// -------------------------------------------------------------------------------------
// codes for component
import { JustAService} from '../justAService.service';
@Component({
  selector: 'app-cute-little',
  templateUrl: './cute-little.component.html',
  styleUrls: ['./cute-little.component.css']
})
export class CuteLittleComponent implements OnInit {
  s: JustAService;
  a: number = 10;
  constructor(theService: JustAService) {
    this.s = theService;
  }

  ngOnInit() {
    this.s.onSomethingHappended(this.doThis.bind(this));
  }

  doThis() {
    this.a++;
    console.log('yuppiiiii, ', this.a);
  }
}
// -------------------------------------------------------------------------------------
// codes for service
@Injectable({
  providedIn: 'root'
})
export class JustAService { 
  private myFunc: () => void;
  onSomethingHappended(fn: () => void) {
    this.myFunc = fn;
    // from now on, call myFunc wherever you want inside this service
  }
}
canbax
  • 3,432
  • 1
  • 27
  • 44
4

as this post is a bit old, I actualize the response of Tudor the stackblitz

the service

private customSubject = new Subject<any>();
  customObservable = this.customSubject.asObservable();

  // Service message commands
  callComponentMethod(value:any) {
    this.customSubject.next(value);
  }

the main-component

constructor(private communicationService:CommunicationService){}
  ngOnInit()
  {
    this.communicationService.customObservable.subscribe((res) => {
          this.myFunction(res)
        }
      );
  }
  myFunction(res:any)
  {
    alert(res)
  }

Another component that call to the method of the service

constructor( private communicationService: CommunicationService  ) { }

  click() {
    this.communicationService.callComponentMethod("hello word");
  }
Eliseo
  • 50,109
  • 4
  • 29
  • 67