Search code examples
jsonangulartypescriptsubject

Using Angular11, how does my HomeComponent retrieve the data provided by the Subject in DataService?


In order to make the data accessible through out the app, I created a new service called the DataService where I want to store my data coming from the API in a Subject. While I do get the data, I cen see the array of objects in a log from DataService, my array in HomeComponent that should get the data is undefined in the console:

browser inspector console output

I imagine I have some stupid errors in my code, I am a beginer. Could you help me ?

HomeComponent:

import {Component, OnInit, Output} from '@angular/core';
import {DataService} from '../../shared/services/data.service';
import {Subscription} from 'rxjs';
import {Article} from '../../shared/models/article';

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.scss']
})
export class HomeComponent implements OnInit {
  @Output() articles?: Article[];
  articleSubscription?: Subscription;
  constructor(private dataService: DataService) { }

  ngOnInit(): void {
    this.dataService.emitArticlesSubject(this.dataService.loadArticles());
    this.articleSubscription =
      this.dataService.articlesSubject.subscribe(
        (articles) => {
          this.articles = articles;
        }
      );
    console.log('HOME COMPONENT: ngOnInit: this.articles : ' + JSON.stringify(this.articles));
  }

}

DataService:

import { Injectable } from '@angular/core';
import {BehaviorSubject, Subject} from 'rxjs';
import {ArticleService} from './article.service';
import {Article} from '../models/article';

@Injectable({
  providedIn: 'root'
})
export class DataService {
  articles?: Article[];
  message = 'Aucun résultat ne correspond à votre recherche.';
  articlesSubject = new Subject<Article[]>();
  constructor(private articleService: ArticleService) { }

  emitArticlesSubject(action: any): void {
    this.articlesSubject.next(action);
  }

  /**
   * Method to be served as a parameter
   * to the 'emitArticlesSubject' method
   * to load articles sorted by date.
   */
  loadArticles(): any {
    this.articleService.getAll().subscribe(
      data => {
        this.articles = data._embedded.articles;
        console.log('DataService: loadArticles() : ' + JSON.stringify(this.articles));
      },
      error => {
        console.log('ERROR: DataService not able to loadArticles !' );
      }
    );
  }
  /**
   * Method to be served as a parameter
   * to the 'emitArticlesSubject' method
   * to load articles sorted by last activity.
   */
  loadArticlesByActivity(): any {
    this.articleService.getAllSortedByActivity().subscribe(
      data => {
        this.articles = data._embedded.articles;
      },
      error => {
        console.log('ERROR: DataService not able to loadArticlesByActivity');
      }
    );
  }
}

ArticleService:

import { Injectable } from '@angular/core';
import {HttpClient, HttpHeaders} from '@angular/common/http';
import {Observable} from 'rxjs';
import {Article} from '../models/article';
import {ResponseEntities} from '../../core/ResponseEntities';

const baseUrl = 'http://localhost:8080/articles';
const queryUrl = '?search=';
const dateUrl = '?sort=date,desc';

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

  constructor(private http: HttpClient) { }

  getAll(): Observable<ResponseEntities<Article[]>> {
    return this.http.get<ResponseEntities<Article[]>>(`${baseUrl}${dateUrl}`);
  }
  getAllSortedByActivity(): Observable<ResponseEntities<Article[]>> {
    return this.http.get<ResponseEntities<Article[]>>(`${baseUrl}/${dateUrl}`);
  }
  search(term: string): Observable<ResponseEntities<Article[]>> {
    return this.http.get<ResponseEntities<Article[]>>(`${baseUrl}/${queryUrl}${term}`);
  }
  get(id: any): Observable<Article> {
    return this.http.get<Article>(`${baseUrl}/${id}`);
  }
  create(data: any): Observable<any> {
    return this.http.post(baseUrl, data);
  }

  update(id: any, data: any): Observable<any> {
    return this.http.put(`${baseUrl}/${id}`, data);
  }

  delete(id: any): Observable<any> {
    return this.http.delete(`${baseUrl}/${id}`);
  }

  deleteAll(): Observable<any> {
    return this.http.delete(baseUrl);
  }

  findByTag(tag: any): Observable<Article[]> {
    return this.http.get<Article[]>(`${baseUrl}?tag=${tag}`);
  }
}

Solution

  • The problem could be related to subscription in data service.

    this.dataService.emitArticlesSubject(this.dataService.loadArticles());
    

    in this line emitArticlesSubject() called. but loadArticles() subscribed to underlaying service. emitArticlesSubject() only call loadArticles() and does not wait for its subscription to get complete. that causes articlss to be undefined. you should use promise in loadArticles() or change your service structures and call ArticleService directly in your HomeComponent.