6

So I know you can have two unrelated components communicate with each other via a service by having one component emit an event in the service and the other subscribe to it in the service.

My question:

Can a service call a function in a component directly?

shammelburg
  • 6,974
  • 7
  • 26
  • 34
Han Che
  • 8,239
  • 19
  • 70
  • 116
  • If you have a reference in your service to the component, sure. But I wouldn't recommend the two classes referring to each other. – Rens Groenveld Mar 30 '16 at 13:12
  • 1
    so basically the event throwing and subscribing method is best practice? – Han Che Mar 30 '16 at 13:13
  • Definetely. You can do that with observers. You want to keep it seperated in order to keep separations of concerns. The answer of Günter seems to be correct. – Rens Groenveld Mar 30 '16 at 13:16

2 Answers2

16

Not by default. A service is an instance of a class, nothing more.

@Injectable()
class MyService {
}

@Component({
  selector: 'my-component',
  ...
)}
class MyComponent {
  constructor(private myService:MyService) {}
}

@NgModule({
  providers: [MyService],
  ...
})
export class AppModule {}

This way a service (MyService) instance gets passed to MyComponent but that is all. The service instance has no knowledge about MyComponent.

What you probably want is to add an Observable to your service and subscribe to it in your component.

@Component({
  selector: 'my-component',
  ...
)}
class MyComponent {
  constructor(myService:MyService) {
    myService.someObservable.subscribe(value => doSomething(value));
  }

  doSomething(value) {
    console.debug(value);
  }
}

this way the service "calls" a method on the component when the Observable someObservable emits another value.

For more details see detect change of nested property for component input

Community
  • 1
  • 1
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • You must ensure the injected MyService in component and the one in other place refer to the same object. Otherwise, the component will fail to respond to the MyService's event. – Chao Jun 30 '16 at 07:26
  • That is by providing it not directoly at the component but on a common parent (or `AppComponent` which is the common parent of the whole application, or in `bootstrap()`) – Günter Zöchbauer Jun 30 '16 at 07:34
  • You are right. I just notice others. you get a nice solution. – Chao Jun 30 '16 at 08:05
  • Better solution would be to use Subject instead of Observers/ables. https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/subjects/subject.md – IvRRimUm Nov 28 '16 at 16:10
  • It would be more helpful if you code provide the service `someObservable` code too – Mohammad Kermani Dec 24 '17 at 14:35
1

The answer above is correct except that you don't bootstrap your service, you will add your service in your providers array in the app.module.

@NgModule({
    declarations: [MyComponent],
    imports: [],
    providers: [MyService],
    bootstrap: [AppComponent]
})

Then you inject your service inside of the component

import { Component } from '@angular/core'

import { MyService } from './path/to/my.service'

...

export class MyComponent {

    constructor(private myService:MyService){}

}
Alvaro Gómez
  • 39
  • 1
  • 4