2

I am trying to call a Method in my Component from a a Service. What is the proper way to do this? I have tried to use rxjs Subject to create an Observable, but I cannot get it to fire.

import {Subject} from 'rxjs/Subject';
    export class MyService {
        callComponent = function(value) {

            let invokeEvent = new Subject();

            invokeEvent.next({some:value})
        }
    }

and in my Component

export class MyComponent {
    constructor(private _myService: MyService) {
             this._myService.invokeEvent.subscribe(value => console.log(value))
           }

}
Rob
  • 11,185
  • 10
  • 36
  • 54
  • I can't draw the relationship between the temporary variable `invokeEvent` in your service and the object `this._myService.invokeViewEvent` that you are using in the component. – Harry Ninh Nov 03 '16 at 04:31
  • sorry typo. It is the invokeEvent that I am trying to listen for. When I call `callComponent` I want to get the Component to fire. I am stuck on observables. – Rob Nov 03 '16 at 04:35

3 Answers3

3

Here's the plunker: http://plnkr.co/edit/WKSurRJMXo5JZOPrwSP5?p=preview

Change your service like this

import {Subject} from 'rxjs/Subject';

@Injectable()
export class MyService {

    invokeEvent:Subject<any> = new Subject();


    callComponent(value) {
        this.invokeEvent.next({some:value})
    }
}

Don't forget to provide it in your component

@Component({
  selector: 'my-component',
  template: `
  `,
  providers: [MyService]
})
export class MyComponent {
       constructor(private _myService: MyService) {
         this._myService.invokeEvent.subscribe(value => console.log(value));
         setTimeout(()=>{
            this._myService.callComponent(1);
         },1000);
       }
}

Also, If you want this service to be a global shared service; put(provide) it in your bootstrap(old) or ngModule so it will share the same singleton instance throughout your app.

eko
  • 39,722
  • 10
  • 72
  • 98
  • Some additional information is that I have exposed my service method to window, outside of angular2 app. So that I can call it like `window.myangular.MyService.callComponent()` I have tried wrapping in zone.run and detechChanges() already. I can see that the call is succesful from consoles in the method. – Rob Nov 03 '16 at 05:19
  • @Rob I've updated my answer with a plunker sir. I'm erasing my previous comments. – eko Nov 03 '16 at 05:33
  • 1
    That did it! The issue was that it didnt like having `MyService` in the `Component` `providers:[ ]`. It required it to be in primary app module only. Strange to me, but thanks a lot. – Rob Nov 03 '16 at 05:42
  • @Rob You should not use` setTimout` for this. – micronyks Nov 03 '16 at 05:44
  • @micronyks why not? – eko Nov 03 '16 at 05:44
  • @echonax why you want to delay it for 1sec even when you can get immediate value once value is omitted.You should not use `setTimeout` instead you can use it with `asObservable()` as shown in my answer. – micronyks Nov 03 '16 at 05:48
  • @micronyks I wanted to value change to be observed with the eye in the view rather than seeing it immediately – eko Nov 03 '16 at 05:54
  • @echonax you can do it even with `asObservable`. `setTimout` is not recommended to use. – micronyks Nov 03 '16 at 05:56
  • I dont have setTimeout in my code. I assumed it was for demonstrating. – Rob Nov 03 '16 at 13:39
1

you can define Observable in service so that you can subscribe to that Observable from component.

//service

import { Injectable, Inject } from '@angular/core';
import { Subject }    from 'rxjs/Subject';
@Injectable()
export class MyService {
  private notify = new Subject<any>();
  /**
   * Observable string streams
   */
  notifyObservable$ = this.notify.asObservable();

  constructor(){}

  public notifyOther(data: any) {
    if (data) {
      this.notify.next(data);
    }
  }

  callComponent(value){
    this.notify.next({some:value});
  }
}

//Component

import { Component, OnInit, OnDestroy } from '@angular/core';
import { Subscription } from 'rxjs/Subscription';

import { MyService } from './my.service';
export class MyComponent {
  private subscription: Subscription;
  constructor( private _myService: MyService ){
  }

  ngOnInit() {
    this.subscription = this._myService.notifyObservable$.subscribe((value) => {
        console.log(value);
    });
  }

  ngOnDestroy() {
    this.subscription.unsubscribe();
  }
}
ranakrunal9
  • 13,320
  • 3
  • 42
  • 43
0
import {Subject} from 'rxjs/Subject';

export class MyService {

        private invokeEvent = new Subject(); 

        invokeEvent$ = this.missionConfirmedSource.asObservable();   //<<< this is important to declare invokeEvent with asObservable(); 

        callComponent = function(value) {
            invokeEvent.next({some:value})
        }
}


export class MyComponent {
    constructor(private _myService: MyService) {
             this._myService
                 .invokeEvent$                                        //<<< subscribe to invokeEvent$ to get the result
                 .subscribe(value => console.log(value))  
           }

}
micronyks
  • 54,797
  • 15
  • 112
  • 146