Is it necessary to compel subscribers to request data from Service again?

I have a straightforward setup, consisting of various elements and a singular service [StackBlitz]:

https://i.sstatic.net/y6AFT.png

Service

@Injectable()
export class Service {
  constructor(private http: HttpClient) {}

  saveItem(item: IItem): Observable<IItem> {
    return this.http
               .post<IItem>('/api/item', item)
               .pipe(map(parseDates));
  }

  retrieveItems(): Observable<IItem[]> {
    return this.http
               .get<IItem[]>('/api/item')
               .pipe(map(parseDates));
  }
}

Element0

@Component({
  selector: 'app-element0',
  template: `<app-element1></app-element1>
             <app-element2></app-element2>`,
  styleUrls: []
})
export class Element0 {}

Element1

@Component({
  selector: 'app-element1-create',
  template: `<button (click)="submit()">Submit</button>`,
  styleUrls: []
})
export class Element1 {    
    constructor(private service: Service) { }

    submit() {
        this.service.saveItem({name: 'example'})
                    .subscribe(console.info, console.error)
    }
}

Element2

@Component({
  selector: 'app-element2-list',
  template: `<pre>{{ items | json }}</pre>`,
  styleUrls: []
})
export class Element2 implements OnInit {
    items: IItem[];

    constructor(private service: Service) { }

    ngOnInit() {
        this.service.retrieveItems()
                    .subscribe(items => this.items = items,
                               console.error)
    }
}

Is there a way for Element1 to update Element2 using the Service?

Answer №1

To enhance your component communication, consider adding another observable:

@Injectable()
export class StoreService {

  private _employes$ = new BehaviorSubject<{id:number,employee_name:string,employee_salary:number,employee_age:number}[]>([]);

  constructor(private _http: HttpClient) {
    this.refresh();
  }

  refresh() {
    this._http.get<{id:number,employee_name:string,employee_salary:number,employee_age:number}[]>('https://dummy.restapiexample.com/api/v1/employees').subscribe(
      data => this._employes$.next(data)
    );
  }

  post() {
      const payload = {"name":"test","salary":"123","age":"23"};

      this._http.post('https://dummy.restapiexample.com/api/v1/create', payload).subscribe(() => {
        this.refresh();
      })
  }

  get employes$(): Observable<{id:number,employee_name:string,employee_salary:number,employee_age:number}[]> {
    return this._employes$.asObservable();
  }
}

This setup consists of two main parts:

An Observable used in your store which allows you to update the stream by calling next on it.

private _employes$ = new BehaviorSubject<{...}[]>([]);

A getter method that any component needing updates from the store can subscribe to.

  get employes$(): Observable<{...}[]> {
    return this._employes$.asObservable();
  }

Based on your specific situation, there are different ways to update this internal observable:

The straightforward approach:

refresh() {
    this._http.get<{...}[]>('...').subscribe(
      data => this._employes$.next(data)
    );
  }

In this method, you subscribe to the HTTP call within the service and update the internal observable.

Pros:

  • Request details are not exposed.
  • Easy maintenance with a single point for API calls.

Cons:

  • May not be suitable for cases requiring specific control over API responses.
  • Subscribing within a service may not always be recommended.

Observable manipulation

If you prefer not to subscribe within the service, you can use the following approach:

return this._http.get<{...}[]>('...')
    .pipe(switchMap(result => {
        this._employes$.next(result);
        return this.employes$;
    }));

This method transforms the HTTP Observable into the internal observable while updating it with the latest API response.

If you require special processing of the API response before making it available across your application, you can do the following:

refresh(myCustomTraitment: = null) {
    return this._http.get<{...}[]>('...')
        .pipe(switchMap(result => {
            if (myCustomTraitment) {
                result = result.map(myCustomTraitment);
            }
            this._employes$.next(result);
            return this._employes$;
        }));
}

Check out this online sample

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Is there a way to verify if a value is undefined before including it as an object field?

I'm currently working on an Angular project and I have a query regarding TypeScript. It's about correctly handling the scenario where a field should not be included in an object if its value is undefined. In my code, I am initializing an object ...

How to conceal an element in Angular using its unique identifier

I am looking for a way to toggle the visibility of an element based on its ID. I have a dynamic list with the following structure in my TS component: vehicles = [ { "id": 1, "type": "car", ...

Integrating Laravel 5.6 with Angular 6 for seamless functionality

For my project, I am considering using Laravel as the backend and Angular as the frontend. There are two methods that I can use to integrate these frameworks: 1) I could integrate both frameworks by utilizing an API service, or 2) I could opt for a monol ...

Incorporate a new method into a TypeScript class from a separate file

I'm curious about the feasibility of adding additional functions to a class prototype in Typescript. Here's my dilemma: I have a file containing a class, for example image.ts: export class Image { b64img: string; } Since this class is gene ...

Using curly braces in a fat arrow function can cause it to malfunction

Could someone provide insight into why this code snippet functions as intended: filteredArray = contacts.filter( (contact: Contact) => contact.name.toLowerCase().includes(term.toLowerCase()) ); while this variation does not: filteredArray = contact ...

Angular2 and ES6 Promise in JavaScript - tackling the issue of undefined variables

I am working with an array of objects like the one shown below: let PAGES = [ new BasePage( 'home', 'test') ]; let pagesPromise = Promise.resolve(PAGES); My goal is to retrieve a BasePage object by calling the following met ...

The command "tsc" was not found in this bash session

Currently, I am using a MAC and attempting to set up TypeScript. I followed the installation process by running sudo npm install -g typescript and received the following output: Password: /Users/<myuserid>/node/bin/tsc -> /Users/<myuserid& ...

Mistakes following update to Angular 4 from Angular 2

After upgrading from Angular2 to Angular4, I encountered these errors in the CLI. While my app continues to function after the upgrade, I am curious about possible solutions to resolve these errors. Any suggestions? https://i.stack.imgur.com/CyYqw.png He ...

AngularJS Kendo Date Picker: A Simplified Way to Select

Having trouble with formatting dates in my local timezone, the date picker is displaying it incorrectly. Here's an example of the code: input id="logdate" kendo-date-picker="logdate" k-options="logdateOptions" data-ng-model="logFilter.date" k-ng-mode ...

When utilizing Monggose, Angular, and Node, a route containing the deleteOne method repeatedly reports that the object has been successfully deleted, despite the delete count remaining

I've encountered a similar issue to others, but their solutions didn't work for me. I'm working on a small MEAN app with mongoose and facing a problem when trying to delete a user or any other object stored in the collection. The route seems ...

In Angular 2+, what is the comparable counterpart to Vue's Vuex?

I have experience with Vue's Vuex, but I am currently working on an Angular application. I would like to implement a similar principle where all components are managed from one central location (like a store in Vue). Is there an alternative to Vuex in ...

Having trouble retrieving form values in Typescript React, only receiving HTML tag as output

I am having an issue with retrieving the form value to my useRef hook as it returns the HTML tag of the form instead. To solve this, I attempted to specify the type HTMLFormElement inside the chevrons and set null as the initial value for my useRef hook. ...

Can data be filtered based on type definitions using Runtime APIs and TypeDefs?

My theory: Is it feasible to generate a guard from TypeDefs that will be present at runtime? I recall hearing that this is achievable with TS4+. Essentially, two issues; one potentially resolvable: If your API (which you can't control) provides no ...

Utilize a ReplaySubject to capture and replay only the most recent value from an observable stream

Here is my ReplaySubject setup: matchCount = new ReplaySubject<number>(); totalCount = new ReplaySubject<number>(); This is how I am utilizing it: getMatchedEventsCount(){ return this.dcs.matchCount.asObservable(); } getTotalEvent ...

Executing a Parent Function from a Child Component in Angular 11

I have successfully passed values between Angular components using Input/Output several times before, but I am currently facing a unique situation for which I cannot find a solution: There are two components involved: home.component (parent component) T ...

Utilizing dynamic data within the ng-template

As a newcomer to Angular, I am facing a challenge in passing a string into a template. My goal is to create a reusable template or component that can display instructions on how to proceed with an action. Currently, I am achieving this by using the follow ...

Arrow functions do not function properly with Typescript decorators

I've created a typescript decorator factory that logs the total time taken to execute a function, along with the actual function execution results and parameters passed to the decorator. For example: export function performanceLog(...args: any[]) { ...

How do I get rid of an unwanted and vulnerable dependency that NPM installed without my consent?

I have come across a vulnerability in my docker image related to a package that I wish to remove. The problematic package can be found at: Upon navigating through the node_modules folder starting from app/node_modules/resolve/test/resolver/multirepo/pac ...

What is the best way to invoke a function in a React component from another component?

I am working with a component structure that includes the Input component. In this component, there is a function called validate that is triggered by the onChange event. Here is a snippet of the code: https://i.sstatic.net/WjCLy.png import React, {FC, us ...

implementing a default reducer using ngrx schematics

I'm having trouble creating a reducer using the ngrx schematics command ng generate @ngrx/schematics:reducer ZipCodes --group When I generate the reducer file, it does not include a default implementation of the reducer export const reducer = createR ...