sHamann
sHamann

Reputation: 799

Angular 2 service calls method from component

Is it even possible to let a service call an component Method?

myapp.component

export class MyAppComponent {
  public value;
  ...
  public setValue(payload){
    this.value = payload;
  }
}

myapp.service

@Injectable()
export class MyAppService {
  private myAppComponent: MyAppComponent;
  private apiClientService: ApiClientService

  // ...
    After i make an PUT http call, the body from the response is my new "value"
  // ...

    putValue(payload: JSON){

    return this.apiClientService.putAPIObject(payload).then((response) => {
      this.myAppComponent.setValue(response);
    }); 
  }
}

This results in an ERROR Error: Uncaught (in promise): TypeError: Cannot read property 'setValue' of undefined.

Can someone explain what im doing wrong? Thanks in advance.

EDIT: Since people complain about my approach, im totally fine to start from scratch if someone can explain me what is the best way to handle this problem.

I get values from an api, change them and i put them back to the api. I dont want to make a get call again, so i get the new data i want in the response of the Put call.

The call goes from component --> component service --> apiclient service

I guess the problem is that i have an extra service between the start and end point.

EDIT 2: I tried to avoid the component service and maked it work for me with only component --> apiclient service

Even this soultion is working for me at the moment I kind of dislike it, because I have to Copy and Paste a lot of code for the Same "Operation" with other objects from my api. For example I maked it work for the Picture Component, but I also need this for my Movie Component. Usally its a bad thing if I write the same code often in a project, or not?

Upvotes: 1

Views: 1968

Answers (1)

stealththeninja
stealththeninja

Reputation: 3791

There are at least a couple ways to solve this, but hopefully this gives you a start. Open to feedback and corrections.

Use an Observable

Let the service own knowledge of the value changes and emit changes. The component listens to an EventEmitter on1 the service to react to value changes. (See also: Creating and returning Observable from Angular 2 Service)

MyAppService

import { Subject } from 'rxjs/Subject';

@Injectable()
export class MyAppService {
  private valueSource = new Subject<any>();
  public valueUpdate$ = this.valueSource.asObservable();

  putValue(payload: JSON){
    return this.apiClientService.putAPIObject(payload).then((response) => {
      /** here **/
      this.valueUpdate$.next(response);
    }); 
  }
}

MyAppComponent

export class MyAppComponent {
  public value;
  private valueSubscription;

  constructor(private _myAppService: MyAppService) {}

  ngOnInit() {
    /** and here **/
    this._myAppService.valueUpdate$.subscribe((p) => this.setValue(p));
  }
  ...
  public setValue(payload){
    this.value = payload;
  }
}

Register the component

Answering the original question, the idea is to register the component with the service so that it can call the component as needed. You could pull a references through dependency injection but wouldn't recommend it (e.g. what if your original component reference is destroyed?)

MyAppService

@Injectable()
export class MyAppService {
  private myAppComponent: MyAppComponent;

  /** here **/
  registerMyApp(myApp: MyAppComponent) {
    this.myAppComponent = myApp;
  }

  putValue(payload: JSON){
    return this.apiClientService.putAPIObject(payload).then((response) => {
      this.myAppComponent.setValue(response);
    }); 
  }
}

MyAppComponent

export class MyAppComponent {
  public value;

  /** and here **/
  constructor(myAppService: MyAppService) {
    myAppService.registerMyApp(this);
  }
  ...
  public setValue(payload){
    this.value = payload;
  }
}
  1. Thanks AJT_82 for noting that Angular does not want developers using EventEmitters on the service: What is the proper use of an EventEmitter?.

Upvotes: 4

Related Questions