Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simplest syntax for exposing a property as an observable?

I've seen tutorials showing umpteen different ways to implement observables in Angular. Many of them seem overly complicated for my purposes. Others are for previous versions and no longer work.

Let's say I have a service with a single property named numChickens, and I want to allow components to subscribe to that property. Do.i.really((need)=> to.chain((a)=>{million.garbledyGook().statements.to('gether)}) to make that work?

Here's the code for the service in question:

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

@Injectable({
  providedIn: 'root'
})

export class ChickenService {

  public chickens: number; 

  constructor() { }

}

...and here is the code for a component which will use the observable:

import { Component, OnInit } from '@angular/core';
import { ChickenService } from '../chicken.service';

@Component({
  selector: 'app-chickendisplay',
  templateUrl: './chickendisplay.component.html',
  styleUrls: ['./chickendisplay.component.scss']
})

export class ChickenDisplayComponent implements OnInit {

  constructor(public cs: ChickenService) {
  }

  ngOnInit() {
  }

}

In Angular 6, what is the simplest, most straightforward, most readable way to expose the chickens property in ChickenService such that a component class has access to the value of that property as an observable stream? Or so that a component template can display the value using an async pipe?

I can't stress that enough - please, no answers that include an 8,192-character wall of closures and then say "see, it's simple".

I ask this question not just for myself, but for others like me who are trying to wrap their heads around observables and struggling with all of the dense and outdated tutorials on the subject. If you can reduce this solution to a simple form, future generations will thank you.

like image 773
Derrick Miller Avatar asked Jan 03 '23 02:01

Derrick Miller


2 Answers

The simplest way would be to create a private Subject, and use that to create your public Observable.

In the code below, I've created a get and set for your chickens variable. This means that each time you update it using (for example) service.chickens = 10, it will automatically trigger a new event on the Observable stream with the new value.

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

@Injectable({
  providedIn: 'root'
})

export class ChickenService {

  private _chickens: number; // Make this private so we can expose it via a get/set
  private chickenChange$ = new Subject<number>(); // This will be used to create our Observable
  public chickens$ = this.chickenChange$.asObservable(); // This is our Observable

  constructor() { }

  set chickens(val: number) {
    this._chickens = val; // Set the new value
    this.chickenChange$.next(val); // Trigger the subject, which triggers the Observable
  }

  get chickens() {
    return this._chickens;
  }

}
like image 190
user184994 Avatar answered Feb 23 '23 00:02

user184994


If you really want to expose it as a stream, all you have to be doing is add a single line:

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

@Injectable({
  providedIn: 'root'
})
export class ChickenService {

  public chickens: number; 
  public chickens$ = of(chickens);
  constructor() { }
}

Note, doing so will still not allow you to update the value, so there not much added value into doing this.

You could use a Subject to make it possible to update the value and reflect those changes in the UI by subscribing the stream:

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

@Injectable({
  providedIn: 'root'
})
export class ChickenService {

  public chickens: number;

  public chickens$ = chickensSub$.asObservable();
  private chickensSub$ = new BehaviorSubject();
  constructor() { }

  updateChickens(value: number) {
    this.chichensSub$.next(value);
  }
}

Note: I try to avoid explicitly using Subjects when not necessary.

like image 22
Frederik Prijck Avatar answered Feb 23 '23 01:02

Frederik Prijck