2
votes

I'm trying to subscribe the changes of variable from angular service without to subscribe it in the component. Here is my code which I tested:

Service:

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

@Injectable()

export class testService {
  detectChanges = new Subject();
  myObject : any = {
    test:"Test"
  };
  constructor() {
    this.detectChanges.subscribe((data) => {
      console.log("changed");
    });
  }
}

Component:

import { Component } from '@angular/core';
import { testService } from './test-service';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  $s;
  constructor(private test: testService) {
    this.$s = this.test.myObject;
  }
}

html:

<input [(ngModel)]="$s.test">
<h1>{{$s.test}}</h1>

Is there any way to do that? like in angularjs $watch Here is an example https://stackblitz.com/edit/angular-cmyy66?file=src%2Fapp%2Fapp.component.html In the example myObject will changes using an input

3
You're looking for BehaviorSubject (which receives push updates), rather than a plan Subject - Z. Bagley
@Z.Bagley I have tryed it, but it works only first time when page is loaded. - ferhado

3 Answers

0
votes

I've created an example on stackblitz

Basically your service looks like this:

@Injectable()
export class TestService{
  private detectChanges: Subject<any> = new Subject<any>();
  myobject$ = this.detectChanges.asObservable();

 constructor() {
   this.detectChanges.subscribe((data) => {
     console.log("changed", data);
   });
 }

 changeObject(myobject: any) {
   this.detectChanges.next(myobject);
 } 
}

to subscribe and make changes to your subject

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  name = 'Angular';

  constructor(private testService: TestService) {
    this.testService.myobject$.subscribe((data) => {
      this.name = data;
    });
  }

  change(input) {
    this.testService.changeObject(input);
  }
}

Hope that helps.

0
votes

You can use a setter for this:

Service:

 private _myObject;
 public get myObject() { return this._myObject; };
 public set myObject(val) { 
     console.log("The value is changing");
     this._myObject = val
 };

In the component:

 constructor(public test: testService) {
    this.test.myObject="New test"; // This would cause "The value is changing" to be logged
 }

If you prefer, in the set function you can instead notify your subject as well

Here is a StackBlitz demo

0
votes

Simplest solution with BehaviorSubject and getter/setter;

@Injectable()
export class testService {
  myObject: any = {
    _test$: new BehaviorSubject("Test"),
    set test(val) {
      this._test$.next(val);
    },
    get test() {
      return this._test$.getValue();
    }
  };
  constructor() {
    this.myObject._test$.subscribe((data) => {
      console.log("changed", data);
    });
  }
}

Also take a look at OnChanges.