Quick filtering of array containing RXJS Observables

As I embark on my Angular2 project, the developers have suggested using RXJS Observable over Promises. So far, I've successfully fetched a list of elements (epics) from the server. Now, my challenge is filtering these elements based on an ID.

Below is a snippet of code from my app showcasing the final solution that worked for me. Hopefully, it proves helpful to others as well.

@Injectable()
export class EpicService {

  private url = CONFIG.SERVER + '/app/';  // URL to web API

  constructor(private http:Http) {}

  private extractData(res:Response) {
    let body = res.json();
    return body;
  }

  getEpics():Observable<Epic[]> {
    return this.http.get(this.url + "getEpics")
      .map(this.extractData)
      .catch(this.handleError);
  }

  getEpic(id:string): Observable<Epic> {
    return this.getEpics()
      .map(epics => epics.filter(epic => epic.id === id)[0]);
  }
}

export class EpicComponent {

  errorMessage:string;
  epics:Epic[];
  epic:Epic;

  constructor(
    private requirementService:EpicService) {
  }

  getEpics() {
    this.requirementService.getEpics()
      .subscribe(
        epics => this.epics = epics,
        error => this.errorMessage = <any>error);
  }

  // this logic ideally belongs in a separate component
  getEpic(id:string) {
    this.requirementService.getEpic(id)
        .subscribe(
        epic => this.epic = epic,
        error => this.errorMessage = <any>error);
  }
}

export class Epic {
  id: string;
  name: string;
}

Your assistance is greatly appreciated. Thank you!

Answer №1

To effectively filter the actual array, ensure you are targeting the array itself and not just the observable that wraps around it. In this case, map the content of the Observable (which contains an Epic[]) to a filtered Epic.

getEpic(id: string): Observable<Epic> {
  return this.getEpics()
     .map(epics => epics.filter(epic => epic.id === id)[0]);
}

Following this, you can then proceed to subscribe to getEpic and make use of the retrieved data accordingly.

Answer №2

Utilize the flatMap and filter methods of Observable instead of the JavaScript array filter method within the context of a map. Here's an example:

this.getEpics() 
    .flatMap((data) => data.epics) // [{id: 1}, {id: 4}, {id: 3}, ..., {id: N}]
    .filter((epic) => epic.id === id) // tests {id: 1}, then {id: 2}, etc
    .subscribe((result) => ...); // take action on the filtered result!

flatMap allows for individual indices for filtering before moving forward with the results.

If TypeScript shows an error stating that you can't compare a string and a number even when using == in the filter, simply add a + before epic.id within the filter function as suggested in the Angular documentation:

    .flatMap(...)
    .filter((epic) => +epic.id === id) // checks {id: 1}, then {id: 2}, etc
    .subscribe(...)

See an example here:

https://stackblitz.com/edit/angular-9ehje5?file=src%2Fapp%2Fapp.component.ts

Answer №3

Here is a modified solution: Observables are considered lazy because you need to use subscribe in order for an observable to make its request.

  getEpic(id:number) {
    return this.getEpics()
           .filter(epic => epic.id === id)
           .subscribe(x=>...);
  }

For Rxjs 6 compatibility:

import {filter} from 'rxjs/operators';

getEpic(id:number) {
        return this.getEpics()
               .pipe(filter(epic => epic.id === id))
               .subscribe(x=>...);
      }

Answer №4

To receive data in JavaScript, it is necessary to subscribe to Observables due to the asynchronous nature of http calls.

fetchData(id: number, displayData: (data: Data) => void) {
    this.getData().subscribe(
        data: Array<Data> => {
            let specificData: Data = data.filter(datum => datum.id === id)[0];
            displayData(specificData);
        }
    );
}

You can use the method above like so:

this.someService.fetchData(dataId, (specificData: Data) => {
    // manipulate the data
});

Answer №5

For those attempting to utilize the flatMap function, please be aware that it is currently deprecated and rxJs strongly suggests using mergeMap as a replacement.

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

"Implementing a loop to dynamically add elements in TypeScript

During the loop session, I am able to retrieve data but once outside the loop, I am unable to log it. fetchDetails(){ this.retrieveData().subscribe(data => { console.log(data); this.data = data; for (var k of this.data){ // conso ...

What is the best way to combine a JSON response object with the variable J inside a for loop?

Received a JSON response as follows: { "name" : "chanchal", "login3" : "1534165718", "login7" : "1534168971", "login6" : "1534168506", "login5" : "1534166215", "login9" : "1534170027", "login2" : "1534148039", "lastname" : "khandelwal", ...

Pass data from Action Class to ajax using JSON syntax

Currently I am facing an issue while working on fullCalendar, a jQuery plugin. I am trying to populate event details from a database when the Calendar page loads, but I seem to be stuck with a silly problem that I can't figure out. $('#calendar& ...

Image pop-ups that overlay text on the homepage

I'm facing an issue and I'm looking for a solution... Upon entering my homepage, I would like to display a popup image showcasing a new event so visitors can see it before accessing the website. I attempted to achieve this using JavaScript but w ...

What is the best way to access a variable within an event handler function?

Is there a way to retrieve values from the for-loop within an event handler? Consider this JSON array var items = [ { "id": "#id1", "name": "text1" }, { "id": "#id2", "name": "text2" } ]; that is passed as a parameter to the function function setHand ...

Angular 12 project with a cutting-edge framework for user interface

Looking to start a new project using Angular 12 and in need of advice on selecting the right UI framework. The options we are considering are Bootstrap 5, Angular Material, and PrimeNG. After conducting some research: Bootstrap 5 is beginner-friendly and ...

AngularJS - Use promise instead of returning a data object

I am currently working on a project using AngularJS. Within my service.js file, I am attempting to retrieve some values. However, instead of receiving the actual data, I am getting back a promise object with some $$variables along with the desired data. ...

Problem with Jquery Ajax, failing to recognize option values

Hello everyone, please review the code snippet below... $.fn.myajax = function (options) { var defaults = { my_event: "", my_url: "", my_data: "", } var o = {}; var mydata = options.my_data; $.extend(o, default ...

Generate an observable by utilizing a component method which is triggered as an event handler

My current component setup looks like this: @Component({ template: ` ... <child-component (childEvent)="onChildEvent()"></child-component> ` }) export class ParentComponent { onChildEvent() { ... } } I am aiming to ...

AdalAngular6ServiceError - Managing Unauthorized Login Attempts

In my Angular 7 application, I am utilizing the ms-adal-angular6 library to handle authentication flow and I am trying to understand the sequence of events in my code. After successfully authenticating with Azure Active Directory (AAD) using a logged-in u ...

The Angular CLI release does not match the Angular version

After updating Angular to version 9, my previously smoothly running angular project started throwing this error: This peculiar error message popped up: This version of CLI is only compatible with Angular versions 0.0.0 || ^10.0.0-beta || >=10.0.0 <1 ...

Error encountered in Jest when trying to use next/font/local: TypeError - (0, _local.default) is not a function

Currently, I am in the process of developing a UI library utilizing MUI, React, and TypeScript within Nx as the build system. To ensure smooth functionality, Jest is being used for testing purposes. However, I recently encountered an issue while attempting ...

What could be causing this code to malfunction when using D3.min version instead?

In this coding example, a scale and an axis object can be seen in the console: <!DOCTYPE html> <head> </head> <body> <script src="//d3js.org/d3.v5.js"></script> <script> console.log(d3.scale ...

Only match the character if it is not at the beginning of the line and if another character is not on the

Is there a way to only match the character "=" in a string if it is not at the beginning of a line and no other character, for example "$", appears on the same line? The equal sign should not be at the beginning of a line No other character, such as "$", ...

The repository injected into NestJs using TypeORM suddenly becomes null

In my code, I am fetching Requisition data from an external system using the following approach: init() { const requisitionData = this.loginMb().pipe( map(response => response.data.token), switchMap(loginData => this.getRequisitions(loginD ...

Is the @Output decorator with EventEmitter functioning properly for sibling components inside <router-outlet>?

Code Snippet from app.component.html <router-outlet> <app-header (cartRefresh)="updateCart(user_id)"></app-header> <app-breadcrumb></app-breadcrumb> </router-outlet> <app-footer></app-footer> Pull Cart Func ...

Deactivate the date when it reaches 8 in the current date count using ajax, php, and mysql

I want to prevent users from selecting a specific date after it has been chosen 8 times. Currently, when the date is selected for the 9th time, an alert box pops up. Instead of the alert box, I would like to disable that particular date selection altogethe ...

Should we consider the implementation of private methods in Javascript to be beneficial?

During a conversation with another developer, the topic of hacking into JavaScript private functions arose and whether it is a viable option. Two alternatives were discussed: Using a constructor and prototype containing all functions, where non-API meth ...

Interactive form control for location details including country, state, district, and town

I am struggling with adding dynamic form controls on dropdown change. I have been able to add them, but encountered an error preventing me from retrieving the value in 'formName.value'. The specific error message states: "Error: There is no Form ...

Binding objects and properties from Angular2/Typescript to a template

Disclaimer: Seeking insight on the correct approach or any additional information _____________________________________________________________________ ANGULAR1 When working with angular1, we had the option to define our objects in the following ma ...