Nikita
Nikita

Reputation: 308

Subscribe to Observable vs subscribe to Subject

There are different methods to get data from server in Angular application:

  1. Get Observable from the service and subscribe to it at component
  2. Create Subject at the service and subscribe to the Subject at component

Both of this methods work for me but I can't understand which should I use.

First method. Get Observable from the service and subscribe to it at component:

article.service.ts

import { Injectable } from '@angular/core';
import { Article } from '../models/article';
import { AngularFirestore } from '@angular/fire/firestore';
import { map, take } from 'rxjs/operators';
import { Observable, Subject } from 'rxjs';

@Injectable({
  providedIn: "root"
})
export class ArticleService {
  public articlesChanged: Subject<Article[]> = new Subject<Article[]>();
  articles: Article[];

  constructor(private db: AngularFirestore) {}

  get() {
    return this.db.collection('articles').valueChanges({ idField: 'id' });
  }
}

home.component.ts

import { Component, OnInit } from '@angular/core';
import { ArticleService } from 'src/app/services/article.service';
import { Observable, Subscription } from 'rxjs';
import { Article } from 'src/app/models/article';

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

export class HomeComponent implements OnInit {
  articles: Article[];

  constructor(private articlesService: ArticleService) { }

  ngOnInit() {
    this.articlesService.get().subscribe(articles => this.articles = articles as Article[]);
  }
}

Second method. Create Subject at the service and subscribe to the Subject at component:

article.service.ts

import { Injectable } from '@angular/core';
import { Article } from '../models/article';
import { AngularFirestore } from '@angular/fire/firestore';
import { map, take } from 'rxjs/operators';
import { Observable, Subject } from 'rxjs';

@Injectable({
  providedIn: "root"
})
export class ArticleService {
  public articlesChanged: Subject<Article[]> = new Subject<Article[]>();
  articles: Article[];

  constructor(private db: AngularFirestore) {}

  get(): void {
    this.db
      .collection('articles')
      .valueChanges({ idField: 'id' }).subscribe(articles => {
        this.articles = articles as Article[];
        this.articlesChanged.next(this.articles);
      });
  }
}

home.component.ts

import { Component, OnInit, OnDestroy } from '@angular/core';
import { ArticleService } from 'src/app/services/article.service';
import { Observable, Subscription } from 'rxjs';
import { Article } from 'src/app/models/article';

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

export class HomeComponent implements OnInit, OnDestroy {
  articlesSubscription: Subscription;
  articles: Article[];

  constructor(private articlesService: ArticleService) { }

  ngOnInit() {
    this.articlesSubscription = this.articlesService.articlesChanged.subscribe(articles => this.articles = articles);
    this.articlesService.get();
  }

  ngOnDestroy(): void {
    this.articlesSubscription.unsubscribe();
  }
}

Is there a best practice which I should use?

Upvotes: 4

Views: 17916

Answers (2)

Yash
Yash

Reputation: 3576

We can say that Subject is a special type of Observable.

Observable: Subscribe to it to get the values.

Subject: Same but you also have control of the values that you want to emit into it (can subscribe to it but also emit) you'll get the default value.

In order to understand the difference between a Subject and an Observable, you need to be aware of two distinct concepts

  • A data producer
  • A data consumer

An observable, by definition is a data producer. That is, a special kind that can produce data over time.

A Subject on the other hand can act as both the – data producer and data consumer.

This implies two things.

  1. A subject can be subscribed to, just like an observable.
  2. A subject can also subscribe to other observables.

That being said, there is one major difference between a subject and an observable.

All subscribers to a subject share the same execution of the subject. i.e. when a subject produces data, all of its subscribers will receive the same data. This behavior is different from observables, where each subscription causes an independent execution of the observable.

Upvotes: 10

Pankaj Shukla
Pankaj Shukla

Reputation: 2672

In your case, it may not make much difference. However, I can see that using subject is leading to extra processing where you first get the data via valueChanges subscription and then push it into a subject then extract data from the subject. This looks unnecessary.

However, think of another component that needs the same data that you get from db valueChanges subscription. In such scenarios you first collect the data from the source, push it into the subject and then multiple components which have subscribed to the same subject, they all get the data. Each component can then independently process the data and do their stuff.

As an example let's say one component triggers some change. As a result of that some processing happens (say on the backend) and data comes back to the service which houses a subject. Data is now pushed to the subject and since multiple components subscribe to this subject, they all get the same data.

As you can see this is very helpful in components communicating with each other in a loosely coupled way. You can create a loosely coupled, flexible, scalable system using this approach.

Upvotes: 1

Related Questions