Search code examples
angularfirebaseangularfire

angular2 - Updating a value based on its previous value


I'm trying to create a blog system that increments the amount of views a certain post has everytime the post is viewed. I'm using firebase for the database and when I go to retrieve the value of the post views, then update it, it continuously increments the value and freezes my browser.. Below is the code I have for it.. Any suggestions?

@Component({
  templateUrl: './post.html',
  styleUrls: ['./post.css']
})

export class Post {
    post: any;

    constructor(db: AngularFireDatabase, router: Router, route: ActivatedRoute){
        route.params.forEach(p => {
            let id = p['id'];
            if(id != null){
                let views = 0;
                let postRef: AngularFireObject<any> = db.object('/Posts/'+id);
                this.post = postRef.snapshotChanges().subscribe(actions => {
                    this.post = actions.payload.val();
                    let v = this.post.views + 1;
                    postRef.update({
                        views: v
                    })
                });
            }else{
                router.navigate(['/']);
            }
        });  
    }
}

Solution

  • The working sample @ https://angular-5urevo.stackblitz.io/

    import { Component, OnDestroy } from '@angular/core';
    import { Router, ActivatedRoute } from '@angular/router';
    import { AngularFireDatabase, AngularFireObject } from 'angularfire2/database';
    import { Subscription} from 'rxjs';
    
    export class PostComponent implements OnDestroy  {
      post: any;  
      postRef: AngularFireObject<any>;
      postRefValueSub: Subscription;
      postRefUpdateSub: Subscription;
    
      constructor(protected db: AngularFireDatabase, protected router: Router, protected route: ActivatedRoute) {
        if(!this.route.snapshot.params['id']) {  
          this.router.navigate(['/']);
          return;
        }
    
        this.postRef = db.object(`/posts/${this.route.snapshot.params['id']}`);
        /* updating post info to view ... */
        this.postRefValueSub = this.postRef.valueChanges().subscribe(value => this.post = value); 
        this.update();  
      }
    
      /* updating post views .... */
      update(value?: any){
        /* increment post's view and unsubscribe to prevent nested looping...  */
        this.postRefUpdateSub = this.postRefUpdateSub || this.postRef.valueChanges().subscribe((value) => {     
            this.postRefUpdateSub = this.unsubscribe(this.postRefUpdateSub);
            this.post = value || this.post || { views: 0 };
            this.post.views++;
            this.postRef.update(this.post);
        });
      }
    
      /* helper to unsubscribe from a subscription ...*/
      unsubscribe(subscription: Subscription) : Subscription {
        if(!subscription) { return subscription; }
        if(!subscription.closed) { subscription.unsubscribe(); } 
        return null;
      }
    
      /* unsubscribing from all subscriptions ... */
      ngOnDestroy(){
        this.postRefValueSub = this.unsubscribe(this.postRefValueSub);
        this.postRefUpdateSub = this.unsubscribe(this.postRefUpdateSub);
      }
    }