Combining Rxjs map and filter to extract countries and their corresponding states from a JSON dataset

I have a unique dataset in JSON format that includes information about countries and states. For example:

 {
  "countries": [
    {
      "id": 1,
      "name": "United States"
    },
    {
      "id": 2,
      "name": "India"
    }],
  "states": [
    {
      "id": 1,
      "countryId": 1,
      "name": "Alabama"
    },
    {
      "id": 2,
      "countryId": 1,
      "name": "Alaska"
    } ] }

With this data, I created a Service to retrieve the countries and states for displaying in dropdown menus:

export class CountriesService {

  constructor(private http: HttpClient) { }

  public getCountries(): Observable<Country[]> {

    return this.http.get<Country[]>("assets/data.json").pipe(map(obj => obj["countries"]));

  }

  public getStates(countryId: number): Observable<State[]> {
    return this.http.get<State[]>("assets/data.json").pipe(
      map(res => res["states"]), 
      map(res => { if (res.countryId === countryId) return res;}));

  }
}

Although the getCountries() method works perfectly, fetching all the countries, I am facing issues retrieving specific states based on the countryId using the getStates method.

Currently, this method is not returning any results. Any idea what might be going wrong?

Answer №1

Ensure to apply the filter once the data is acquired.

export class CountriesService {
  constructor(private http: HttpClient) { }

  public getCountries(): Observable<Country[]> {
    return this.http.get<Country[]>("assets/data.json").pipe(
      map(obj => obj["countries"]),
    );
  }

  public getStates(countryId: number): Observable<State[]> {
    return this.http.get<State[]>("assets/data.json").pipe(
      map(res => res["states"]), 
      withLatestFrom(of(countryId)),
      map((id, states) => states.filter(state.countryId === id)),
    );
  }
}

It is also recommended to merge all information together to prevent multiple requests for state data which remains constant.

export class CountriesService {

  constructor(private http: HttpClient) { }

  public getCountriesWithStates(): Observable<Country[]> {
    return this.http.get<Country[]>("assets/data.json").pipe(
      map(data => data.countries.map(country => ({
        ...country,
        states: data.states.filter(state => state.countryId === country.id),
      }))),
    );
  }
}

service.getCountriesWithStates().subscribe(countries => {
// countries[0].states[0];
});

Answer №2

When the API call returns an observable, it is actually emitting an array due to your map function, not an array of observables. Therefore, the second map function you are using is not functioning as expected. Instead, within the first map, you can filter out the states that have the desired country id by utilizing a method called filter which is available on JavaScript arrays.

public getStates(countryId: number): Observable<State[]> { return this.http.get<State[]>("assets/data.json").pipe( map(res => res["states"].filter(res => res.countryId === countryId)); }

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

Where specifically in the code should I be looking for instances of undefined values?

One method in the codebase product$!: Observable<Product>; getProduct(): void { this.product$ = this.route.params .pipe( switchMap( params => { return this.productServ.getById(params['id']) })) } returns an ...

Incorporating and designing a side button using jQuery Mobile

I'm working on adding a button to the left side of the screen that is round (but not necessarily) and partially visible, with a visually appealing design. This button will allow users to open a side menu panel. Below is the HTML code for the button: ...

Guide for converting a JavaScript function with spread arguments of different types to C# style

I am having difficulty with the strict typing in C# when it comes to function arguments. For my Reverse Polish Notation (RPN) calculator, the required arguments will be passed through a function call using a comma-separated list of different types: this.F ...

Creating HTML input elements dynamically using Javascript

<body> <form action="insertquestion.php" method="POST"> <script> function generateInputs(){ var prefix = "answer"; var number = 1; for(var i = 0; i < 5; i++){ ...

Is it possible for numerous identical components to trigger the display of the identical modal on a single webpage?

I am currently utilizing Vue in my project and I have a component that displays a button. When this button is clicked, it triggers a modal to open which is also part of the same component. The functionality works as intended. However, if there are multipl ...

Tips for Implementing Cache Busting in Angular Universal

Is there a way to execute cache busting in Angular Universal? I attempted to run the command npm run build:ssr --output-hashing=all but it did not make any changes. PACKAGE.json "scripts": { "ng": "ng", "start": "ng serve", "build": "ng bui ...

Discover a method to receive an alert when the mouse exits the inner window along the y-axis

Is there a way to receive an alert if the mouse moves out of the inner window solely in the y-axis? Currently, alerts are triggered when the mouse moves out on both x-axis and y-axis. For example, if the mouse pointer hovers over the address bar coming fro ...

Exploring the functions of the elasticsearch javascript library: Understanding the search_type feature

Currently, I am attempting to run a search query using search_type of count with the elasticsearch.angular.js version sourced from the npm module. The query can be successfully executed as follows: POST /index1/type1/_search?search_type=count { " ...

Error message: "When using selenium-webdriver in JavaScript, the findElement method for <a> tags cannot be used as a function."&

Seeking the website URL for brand information from this website, I attempted to retrieve it using JavaScript in the console: document.getElementById('phone_number').getElementsByTagName('a')[1].getAttribute('href') However, ...

Mastering the use of npm and sails to create HTML-PDF files effortlessly

UPDATE: I am simplifying my question and will address any other concerns in separate posts if necessary. The initial post was too lengthy, hoping for a straightforward guide on utilizing sails to its fullest potential. Apologies. To begin with, my knowled ...

Struggling to send information to the data layer on every page in Angular 9

Currently, I am in the process of integrating a GTM snippet into my Angular project. However, I have noticed that when the page is hard reloaded, it pushes data but does not do so during normal navigation. I have already added the GTM snippet provided by ...

Avoiding content resizing when using a drawer in Material UI

My project features a drawer that expands, but I am encountering an issue where the content inside the drawer resizes when expanded. However, this is not the desired outcome. I want the expanded drawer to overlay the content without resizing it. How can I ...

Why is interpolation not allowed in Angular 2 for binding to my child component?

If I plan on assigning the 'src' attribute of an 'image' tag, I have the option to use either <img src='{{heroImageUrl}}'> or <img [src]='heroImageUrl'> However, when dealing with a child component us ...

Narrow down JSON data by chosen element

Utilizing the autocomplete feature, I have created a system to display options based on a JSON file. My current objective is to filter the JSON data according to the selected item. For example, if I select "Roma" from the autocomplete input, I want to dis ...

React Material-UI - implementing custom colors in Alert component leads to error: "Cannot read properties of undefined (reading 'type')"

I've been working on customizing MUI components to match our company's design, but I've hit a roadblock. While defining my custom colors, I noticed that instead of "error" we have a color called "danger." I followed the guidelines in the do ...

What is the best way to determine if the current page in Ionic 2 is being loaded from the sidemenu?

In my Ionic 2 application, there is a page that can be accessed either by clicking on a link in the sidenav or being active by default when the app is loaded. However, I want to implement an additional feature only when the page is accessed through the sid ...

Error code TS7053 occurs when an element implicitly has an 'any' type because a string expression cannot be used to index an empty object

I have implemented a code snippet that sorts items into groups based on their first character. For example, if the array of item looks like this: {name: 'Foo'} {name: 'Bar'} {name: 'Baz'} The expected result should be: B: ...

Encountering an issue with Invariant Violation when attempting to retrieve a frame that is outside of the specified

I have created a VenueList component for my React Native app. I want to utilize the FlatList component to display a list of venues, but I keep encountering an error message that says "Invariant Violation tried to get frame out of range index" (refer to the ...

What is the process for displaying or hiding a large image when clicking on thumbnail images?

How can I toggle the display of a large image by clicking on thumbnails? This is what I am looking for: Check out this JSFiddle version http://jsfiddle.net/jitendravyas/Qhdaz/ If not possible with just CSS, then a jQuery solution is acceptable. Is it o ...

Troubleshooting the importing of external data to a D3.js tree diagram

Can anyone provide assistance with debugging my script? I am experiencing difficulties loading external data from a JSON file. The script works fine when the data is stored in a variable within the code, but not when it is separated into a file. <!DO ...