34

I think I misunderstand how Observables are supposed to be used. I want to put a value in, and when the value changes it should emit the new value. I thought that was what they were for, but all the tutorials and docs don't seem to do this, but at the same time, I always see them being applied this way. For example, in angular when you subscribe to a "FirebaseListObservable", when the value in firebase changes it fires off a snapshot in the subscription. I want to make that for my own variable. Let's say I just have a string variable, and when it changes, it fires off any subscriptions.

Dino
  • 7,779
  • 12
  • 46
  • 85
Jus10
  • 14,519
  • 21
  • 52
  • 77
  • 2
    If you want to put new values into the stream yourself you want a *Subject*, not just an *Observable*. Most Observables are effectively read-only. But that won't necessarily *detect* the change, you'll have to manage it yourself. – jonrsharpe Sep 09 '17 at 15:07
  • http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html – Amit Kumar Singh Sep 09 '17 at 15:08
  • YES Thank you. So many hours researching observables and no one ever even mentions Subject. That makes more sense. Thank you for clarifying! – Jus10 Sep 09 '17 at 15:10
  • I wrote a bit about how we've been using Subjects here if that's of use: https://blog.jonrshar.pe/2017/Apr/09/async-angular-data.html – jonrsharpe Sep 09 '17 at 15:11
  • 1
    Oh wait, so there is no built-in change-detection for variables anywhere in rxjs? I have to manually work that out? I definitely thought that was a built-in feature lol – Jus10 Sep 09 '17 at 15:24
  • har har, turns out i have spent a year almost becoming competent at HALF of rxjs... golly. That makes me sad. – greg Jan 29 '23 at 21:06

2 Answers2

57

Normally I would have my observables in services that get subscribed to in components, but I bundled them all in one class for the convenience of this answer. I've listed comments explaining each step. I hope this helps. : )

import { Subject } from 'rxjs/Subject';

export class ClassName {
    // ------ Creating the observable ----------
   // Create a subject - The thing that will be watched by the observable
   public stringVar = new Subject<string>();

   // Create an observable to watch the subject and send out a stream of updates (You will subscribe to this to get the update stream)
   public stringVar$ = this.stringVar.asObservable() //Has a $ 

   // ------ Getting Your updates ----------
   // Subscribe to the observable you created.. data will be updated each time there is a change to Subject
   public subscription = this.stringVar$.subscribe(data => {
         // do stuff with data
         // e.g. this.property = data
   });

  // ------ How to update the subject ---------
   // Create a method that allows you to update the subject being watched by observable
   public updateStringSubject(newStringVar: string) {
     this.stringVar.next(newStringVar);
   }
   // Update it by calling the method..
   // updateStringSubject('some new string value')

   // ------- Be responsible and unsubscribe before you destory your component to save memory ------
   ngOnDestroy() {
     this.subscription.unsubscribe()
   }
}
Jonathan002
  • 9,639
  • 8
  • 37
  • 58
  • 1
    This is great. Aren't Subjects already Observables? Is there a difference between subscribing to the subject itself, and subscribing to the observable version of the subject? – Jus10 Sep 09 '17 at 16:49
  • 21
    Pretend the subject is some sort of animal and the observable is the camera documenting the subject. If the subject is asleep the observable will stream asleep as an event. You subscribe to this by watching animal planet's documentary on tv haha – Jonathan002 Sep 09 '17 at 16:51
  • But technically speaking, yeah the subject does need to exist for the observable to observe them and emit the changes to whatever subscriptions you have active – Jonathan002 Sep 09 '17 at 16:53
  • Glad to have helped ^^ – Jonathan002 Sep 09 '17 at 16:54
  • 1
    This is just perfect wanted an example just like this, simple and clean – Dev Man Oct 02 '18 at 17:09
  • @Jonathan002 nice observation on this subject – refaelio Dec 04 '19 at 12:37
0

Try this using ReplySubject. I used typescript, angularfire to explain in the below code example

export class MessageService {
  private filter$: ReplaySubject<any> = new ReplaySubject(1);

  getMessagesOfType():FirebaseListObservable<any>{
   return this.af.database.list(this.messagesPath, {
    query: {
      orderByChild: 'type',
      equalTo: this.filter$
    }
  });
  }
  getClosedMessage(): void {
    this.filter$.next('closed');
  }
  getOpenMessage(): void {
    this.filter$.next('open');
  }
}

// in some other class
// MessagesSubject is assigned to messageService 
this.messageService.getMessagesOfType().subscribe((listOfMessages)=>{
 // this list will be updated when the this.filter$ updated see below functions
 console.log(listOfMessages); 
});
// update this.filter$ like this to get 
this.messageService.getClosedMessage();
// to get open messges in 
this.messageService.getOpenMessage();
nagabandaru
  • 605
  • 7
  • 20
  • Not really what I'm looking for. In this case, the FirebaseListObservable is doing the change detection for us, and it's based on changes in the database. I'm just trying to implement change-detection on a string variable really. – Jus10 Sep 09 '17 at 15:59