Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding/Deleting an object to an Obervable of an object array in Angular/RXJS?

Goal: To add an object to an existing Observable array of objects. Having this reflect on the DOM is the final step.

NewObject.ts:

export class NewObject {
  name: string;
  title: string;
}

Here's the example.component.ts:

import { Observable } from 'rxjs';
import { Component, OnInit, Inject, EventEmitter } from '@angular/core';
import { NewObject } from 'objects';

@Component({
  selector: 'app-example',
  templateUrl: './example.component.html',
  styleUrls: ['./example.component.css']
})
export class ExampleComponent implements OnInit {

  // Initializing the object array Observable from a service (step 1)
  readonly objects$: Observable<NewObject[]> = this.objectSvc.getAllObjects("objects").pipe(
    map(obj => obj.map(x => ({ name: x.name, title: alterString(x.title) }))),
    shareReplay(1)
  );

  constructor(
    private objectSvc: ObjectService
  ) { }

  ngOnInit() {

    somethingThatHappensToAdd = (response: any) => {
      let data = JSON.parse(response);
      data.forEach(x => {
        let obj: NewObject = { name: x.name, title: alterString(x.title) }

        // Here's where I'm trying to add the obj object into the already existing object array Observable
      });
    };

    somethingThatHappensToDelete = (response: any) => {
      let data = JSON.parse(response);
      data.forEach(x => {
        let obj: NewObject = { name: x.name, title: alterString(x.title) }

        // Here's where I'm trying to delete the obj object from the already existing object array Observable
      });
    };

  }
}

This is my example.component.html:

<div *ngFor="let o of objects$ | async">
   <p>{{ o.name }}</p>
   <p>{{ o.title}}</p>
</div>

Here's my service object.service.ts:

import { Injectable } from '@angular/core';
import { Observable, throwError, of } from 'rxjs';
import { map, catchError } from 'rxjs/operators';
import { ClientApi, ApiException, NewObject } from '../client-api.service';

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

  constructor(
    private clientApi: ClientApi
  ) { }

  getAllObjects(name: string): Observable<NewObject[]> {
    return this.clientApi.getAllObjects(name)
      .pipe(
        map((x) => x.result),
        catchError(err => {
          if (ApiException.isApiException(err)) {
            if (err.status === 404) {
              return of<NewObject[]>(undefined);
            }
          }
          return throwError(err);
        })
      );
  }
}

After formatting of the response in JSON, I want to be able to insert the obj object into objects$ Observable and have it reflect on the UI.

I am advised to use a BehaviorSubject element to make this happen. Can anyone advise on how this can be easily done?

like image 223
LatentDenis Avatar asked Nov 20 '25 06:11

LatentDenis


1 Answers

You can create a BehaviorSubject to emit results coming from somethingThatHappens() and use combineLatest() to merge the results with the ones coming from the service.

objectsFromService$ = this.objectSvc.getAllObjects("objects").pipe(
    map(obj => obj.map(x => ({ name: x.name, title: alterString(x.title) })))
);

resultsArray = []
resultsSubject = new BehaviorSubject(this.resultsArray);
results$ = this.resultsSubject.asObservable()

readonly objects$: Observable<NewObject[]> = combineLatest(
    this.results$,
    this.objectsFromService$
).pipe(
   map(([results, objects]) => ([...results, ...objects])),
   shareReplay(1)
)


somethingThatHappens = (response: any) => {
      let data = JSON.parse(response);
      data.forEach(x => {
        let obj: NewObject = { name: x.name, title: alterString(x.title) }
        this.resultsArray.push(obj)          
      });
      this.resultsSubject.next(this.resultsArray)
};

I created a working stackblitz project: https://stackblitz.com/edit/angular-jnngwh

Hope this gives you a clue.

like image 184
Harun Yilmaz Avatar answered Nov 23 '25 01:11

Harun Yilmaz