Home > front end >  Create an Observable with a new value in the Service and access it in two different Components
Create an Observable with a new value in the Service and access it in two different Components

Time:05-25

I'd like to access the Observable's value coming from a Service in two different components.

This is how I'm trying to do it:

// My service holding on Observable and initialising it with a value of 1,
// then resetData() creates a new Observable with a value of 0.
@Injectable({
  providedIn: 'root',
})
export class DataService {
  data$;

  constructor() {
    this.data$ = of(1);
  }

  getData() {
    return this.data$;
  }

  resetData() {
    this.data$ = of(0);
  }
}

Then I try to call resetData() in cmp1 Component but the new value is not there.

@Component()
class cmp1 implements OnInit {
  data$: Observable<number>;
  data: number;
  constructor(private dataService: DataService) {}

  ngOnInit() {
    this.data$ = this.dataService.getData();
    this.data$.subscribe((value) => (this.data = value));
    console.log(this.data); // should be 1
  }

  doStuff() {
    this.dataService.resetData();
    console.log(this.data); // should be 0
  }
}

I also try to access that same value in a different component and the value is also not there:

@Component()
class cmp2 implements OnInit {
  data$: Observable<number>;
  data: number;
  constructor(private dataService: DataService) {}

  ngOnInit() {
    this.data$ = this.dataService.getData();
    this.data$.subscribe((value) => (this.data = value));
    console.log(this.data); // should be 1
  }

  doStuff() {
    this.dataService.resetData();
    console.log(this.data); // should be 0
  }
}

There are two questions here to answer this fully:

  • How to access a value of the Observable coming from a Service in a Component?
  • How to access a value of the Observable coming from a Service in two different Components?

CodePudding user response:

I'm assuming that the subscription's first value is firing, ie you're writing 1 to the console? And the problem is that you don't get any more updates after calling resetData()? If so, that is due to you re-initializing the Observable. You're overwriting it basically, making any previous subscriptions obsolete.

What your method could do, is something like

resetData(): void {
  this.data$.next(0);
}

CodePudding user response:

You should take the time to learn more about Observables because it is a required knowledge and should be well understood. There is plenty of resources about them.

Firstly, a common mistake is to think values will be available out ouf the subscription:

this.dataService.resetData();
console.log(this.data); // should be 0

If the observable needs few seconds to send the result then this.data will still have the old value when you log it.

You should log new values inside the subscription:

this.data$.subscribe((value: number) => {
    this.data = value;
    console.log(this.data);
});

Also, as @Aldin Bradaric answered, when you do:

this.data$ = of(0);

then you create a new object but your components still have subscriptions to the old one.

About your needs, you should use Subjects rather than Observables: have a look to What is the difference between Observable and a Subject in rxjs?)

Then your service will be like:

export class DataService {
  data$: Subject<number> = new ReplaySubject();

  constructor() {
    this.data$.next(1);
  }

  getData() {
    return this.data$;
  }

  resetData() {
    setTimeout(() => {
      this.data$.next(0);
    }, 1000)
  }
}
  • Related