Search code examples
angulartypescriptfirebaserxjsangularfire2

Angular 8 , Firebase angular fire2 how to find an observable's state change


I use angular fire 2 , firebase and angular to develop a project. There is a notification component. So I want to display an alert whenever the content changed in an observable. Is there a way to do that ?

Here is my code: I want to display alert("Notification") whenever the content of the item obeservable changed .

      import { Component, OnInit } from '@angular/core';
      import { AngularFirestoreDocument, AngularFirestoreCollection, AngularFirestore } from 'angularfire2/firestore';
      import { Observable } from 'rxjs';

      export interface Item { age: string; name: string; data: string }
      @Component({
        selector: 'app-notifications',
        templateUrl: './notifications.component.html',
        styleUrls: ['./notifications.component.scss']
      })
      export class NotificationsComponent   {


        private itemDoc: AngularFirestoreDocument<Item>;
        item: Observable<Item>;
        oldItem:any ;//this is for tack document changes 
        public user ;
        itemsCollection: AngularFirestoreCollection<Item>;


        constructor(public  afs: AngularFirestore) {
            this.itemDoc = afs.doc<Item>('Notifications/5xmXcPPVmPgWi4uttnN2v6rrMmD2/1235/fEsNdG9LaHNPK2f3LYuH/');
            this.item = this.itemDoc.valueChanges();

          }

          update(item: Item) { 
            this.itemDoc.update(item);
          }


        public   addItem(name: string , age:string , data:string) {
          this.itemsCollection = this.afs.collection<Item>('Notifications');
          const id = this.afs.createId();
          const item: Item = { age , name , data };
          this.itemsCollection.doc('5xmXcPPVmPgWi4uttnN2v6rrMmD2/1235/fEsNdG9LaHNPK2f3LYuH/').set(item);
        }

        public test(){
          this.addItem('Ama1l'  , 'Namal' , 'Sujit');
        }


      } 

I am a beginner here . So some terms may be wrong sorry for that . I would be much thankfull to you if you could supply an explanation to resolve this issue. Thank you !!


Solution

  • all variable with super type Observable have method subscribe().

    this method receive 3 parameters (and 2 are optional).

    On your Line 24 you can do :

    this.item = this.itemDoc.valueChanges();
    this.item.subscribe(
       (item) => alert("Notification"), // Will be called on any value changes.
       (err) => console.log(err), // Optional params : will be called if error occur.
       () => console.log('stream is finished') // Optional params: will be called just before stream is finished and will not have any value change anymore.
    );
    

    RxJS and observable are powerful tools base on stream and async concept. An observable can be consider as stream of data which occur on timeline.

    This stream can be manipulate by operator. Your case is to ignore the first emited value from your stream, then react to all futur one. It exist one operator call skip which allow you to skip N first emission on your stream.

    this.item.pipe(skip(1)).subscribe([...])
    

    From your original stream create new one where the first emitted value will be ignored.


    Important information : observable subscription are destroy only on this two following case :

    • if observable have error or complete the stream.
    • if subscription is unsubscribe.

    than means on your case, if NotificationsComponent is destroyed (remove from DOM). Subscription will still be subscribed and you will still have your alert on any change, doesn't matter if you component still exist or not.

    to prevent this probably unexpected behavior. you have to store the subscription and unsubscribe on OnDestroy life cycle hook.

      export class NotificationsComponent  implement OnDestroy {
        [...]
        item: Observable<Item>;
        subscriptionItem: Subscription = null;
        [...]
    
    
        constructor() { 
          this.subscriptionItem = this.item.subscribe([...]);
        }
    
        ngOnDestroy() {
            if (this.subscriptionItem !== null)
                this.subscriptionItem.unsubscribe();
        }
    }