Creating a nested observable in Angular2: A step-by-step guide

Currently, I am exploring a new approach in my Angular2 service that involves using observables. The data source for this service will initially be local storage and later updated when an HTTP call to a database returns. To achieve this dynamic updating of data from various sources, I believe utilizing observables is the way to go. Although I am skipping the local storage aspect for now to focus on understanding the concept, it's essential to mention the rationale behind wanting to implement multiple methods.

My initial plan was to create a "getHTTPEvents()" method that would return an observable containing events fetched from the DB. This setup allows for the potential addition of a 'getLSEvents()' method in the future.

To simulate this functionality, I have the following code snippet:

private eventsUrl = 'app/mock-events.json';
getHTTPEvents(): Observable<Array<any>> { 
    return this._http.get(this.eventsUrl)
        .map(response => response.json()['events'])
        .catch(this.handleError); // handle error is a logging method
}

My objective is to develop a method that permits filtering of returned events while still providing an observable to the service users. Here lies my challenge. To address this goal, I'm creating a public method that consumers of the service will utilize (inspired by a pattern found at this resource).

public getEvents(key: string, value: string): Observable<Array<any>> {
    var allEventsObserve: Observable<Array<any>> = this.getHTTPEvents();
    var filteredEventsObserve: Observable<Array<any>>;

    allEventsObserve.subscribe(
        events => {
            for(var i=0; i < events.length; i++) {
                if(events[i][key] == value) {
                    console.log('MATCH!!!' + events[i][key]); // THIS WORKS!
                    return new Observable(observer => filteredEventsObserve = observer);
                }
            }
            return allEventsObserve;
        },
        error => console.error("Error retrieving all events for filtering: " + error));
}

The above implementation does not function as expected. Despite watching tutorials and reading extensively about observables, I've struggled to find resources delving deeper than basic HTTP observables handling.

I also attempted this alternative approach for creating a new observable:

var newObs = Observable.create(function (observer) {
    observer.next(events[i]);
    observer.complete(events[i]);
});

While this compiles, I am uncertain about how to 'return' it at the appropriate moment. I am unable to create it outside the allEventsObserve.subscribe method due to the absence of 'events,' and returning it within the subscribe seems ineffective. How can I then trigger the 'next' event? Do I need to modify the data within allEventsObserve or generate a new observable with the correct payload - and if so, how do I initiate it?

I consulted resources like this Stack Overflow thread but struggle to grasp how the 'second' observable gets activated. Perhaps my entire approach to this paradigm is flawed?

Answer №1

It seems like there might be a misunderstanding regarding the output of RxJS operators (such as map, filter, etc) and clarifying that could lead to a clearer solution.

Let's look at this brief example:

allEventsObserve
  .map(events => {
    return 'this was an event';
  })

Although it's not very useful since all data from events is discarded, for now let's overlook that fact. The code above does not produce an array of strings; instead, it returns another Observable. This new Observable simply emits the string 'this was an event' for each array of events emitted by allEventsObserve. This chaining of operators on observables is enabled because each operator in the chain generates a fresh Observable emitting modified items based on the previous operator.

allEventsObserve 
  .map(events => {
    return 'this was an event';
  }) 
  .filter(events => typeof events !== 'undefined') 

allEventsObserve is evidently an Observable, allEventsObserve.map() results in an Observable, just like allEventsObserve.map().filter().

Therefore, if you anticipate your function returning an Observable, refrain from subscribing right away as doing so would give back something that doesn't truly qualify as an Observable.

To illustrate this point, here's a revised version of your code:

public getEvents(key:string,value:string) : Observable<Array<any>> {
    var allEventsObserve : Observable<Array<any>> = this.getHTTPEvents();

    return allEventsObserve 
      .map(events => {
          var match = events.filter(event => event[key] == value);
          if (match.length == 0) {
            throw 'no matching event found';
          } else {
            return match[0];
          }
      })
      .catch(e => {
        console.log(e);
        return e;
      });

}

Since getEvents yields an Observable, you would typically interact with them elsewhere in your code using something like

getEvents().subscribe(events => processEvents())
. Additionally, note that I replaced your for loop with a call to filter, which works on arrays. In this scenario, events represents a standard JavaScript Array, so the filter being invoked is not the same as the RxJS operator filter.

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

Confused about the functionality of the map feature in Angular

I am new to Angular and currently working on an application that utilizes the typeahead functionality. I have set up a HTTP call through my Express backend on GCP to fetch search results from the TMDB database based on a search keyword. this.http .ge ...

What is the best way to trigger a unique modal dialog for every element that is clicked on?

I simply want to click on the state and have that state's specific pop-up appear. $("path, circle").on('click', function(e) { $('#info-box').css('display', 'block'); $('#info-box').html($(this ...

What is the best way to disengage a loop of elements within an internship?

In my scenario, the DOM structure is as follows: <table id="campaigns"> <tr> <th>Name</th> <th>Status</th> </tr> <tr> <td>first data</td> </tr> <tr data- ...

Error: The function res.getHeader is not recognized within the Next.js API environment

I am currently working on a web application using NextJS 13, TypeScript, Next Auth v4, Prisma (using SQLite for development), and OpenAI. While accessing the API endpoint, I encountered an error in the console with the following message: error - TypeError ...

The choice between using inline style objects with React or utilizing traditional CSS classes presents distinct advantages and

Is there a discernible difference between utilizing an inline style object for react components and using a normal CSS class through the className attribute? Even when wanting to modify styles based on a specific event, simply changing the className should ...

Unable to locate the value of the query string

I need help finding the query string value for the URL www.example.com/product?id=23 This is the code I am using: let myApp = angular.module('myApp', []); myApp.controller('test', ['$scope', '$location', '$ ...

Initializing the ngOnInit function with 'this' keyword

I've encountered a scope issue where the lines "this.catVotes = catData" are within another function, preventing me from directly assigning it to "catVotes: Number;" Any suggestions on how I can overcome this challenge? catVotes: Number; dogVotes: N ...

A guide on iterating through a JSON object in Vue and Javascript to retrieve keys and values, checking if they are either distinct or null

Looking for a way to iterate through a JSON object that may or may not have properties fields, which can be null or contain various configurations. I need to display it in a code block. Below is the example JSON data: "grade": [ { ...

Conceal the menu in Angular Material when the mouse leaves the button

When the mouse hovers over a button, a menu is displayed on the website's toolbar. The menu is set to close when the mouse leaves a surrounding span element. Now, there is an attempt to also close the menu when the mouse leaves the triggering button i ...

$q.all - successfully resolving some HTTP requests while encountering errors on others

I encountered a coding scenario like this angular.forEach(config.tvshows.shows, function(show) { promises.push($http.get('http://epguides.frecar.no/show/' + show.replace(/\s|\./g, '') + '/next/')); }); re ...

What are the steps for making Ajax calls?

I have been working on a Wikipedia viewer for my freecodecamp project. However, I am facing issues with the AJAX request as it keeps failing every time without returning any results. var url, value; $(document).ready(function() { $("button").on("click ...

Guidelines for dynamically displaying <router-link> or <a> in Vue based on whether the link is internal or external

<template> <component :is="type === 'internal' ? 'router-link' : 'a'" :to="type === 'internal' ? link : null" :href="type !== 'internal' ? link : null" > <slot /> < ...

Apply CSS styles when the text exceeds the size of the textbox

Is there a way to create a textbox that scrolls on hover only if the text is longer than the textbox itself? Check out my attempt here: https://jsfiddle.net/SynapticError/wqh4ts3n/35/ The text should scroll on hover if it's longer than the textbox. ...

Guidelines on Transferring Variables to a JavascriptExecutor Script

Currently, I am utilizing C# and Selenium to browse through a website and have come across an issue regarding passing variables into my JavaScriptExecutor command. When I attempt to do so using the code below: ((IJavaScriptExecutor)webdriver).ExecuteScript ...

npm ERROR! 404 Content removed by unidentified source on August 8, 2022 at 09:20:35.527 UTC

Upon running the command <npm view e-biz-znnf versions --json> in the terminal, npm throws an error message: npm ERR! code E404 npm ERR! 404 Unpublished by undefined on 2022-08-08T09:20:35.527Z npm ERR! 404 npm ERR! 404 'e-biz-znnf' is no ...

"Exploring the concept of Undefined in Javascript Arrays

I keep encountering the issue links[i] is undefined. Even after explicitly defining it, the error persists. Any thoughts on why this might be happening? I am attempting to implement unobtrusive image rollovers for 5 links that I currently have. function ...

Using jQuery's slideToggle feature to hide content when clicked again or when a different button is

I have a challenge with creating toggle buttons that require specific functions: 1) Display content on the first click (this is working) 2) Conceal content when another button is clicked (this is also working) 3) Hide content on the second click (this i ...

Triggering multiple updates within a single method in Angular will cause the effect or computed function to only be triggered

Upon entering the realm of signals, our team stumbled upon a peculiar issue. Picture a scenario where a component has an effect on a signal which is a public member. In the constructor of the component, certain logic is executed to update the signal value ...

Alternatives to using wildcards in TypeScript

In my code, I have defined an interface called ColumnDef which consists of two methods: getValue that returns type C and getComponent which takes an input argument of type C. Everything is functioning properly as intended. interface ColumnDef<R, C> { ...

The app is having trouble loading in Node because it is unable to recognize jQuery

I am currently using Node to debug a JavaScript file that includes some JQuery. However, when I load the files, the $ sign is not recognized. I have installed JQuery locally using the command npm install jquery -save-dev. The result of "npm jquery -versio ...