Exploring the Functionality of Observables and HTTP Requests in Angular

When I use the http get method in Angular, it returns an observable. To test this, I created a local server that serves up a 50 MB JSON file containing all employee data.

import { Injectable } from "@angular/core";
import { Http } from "@angular/http";
import 'rxjs/add/operator/map';
@Injectable()
export class DataServiceService {
  constructor(private _http: Http) {}

  getEmployeeData() {
    return this._http
      .get("http://localhost:3000/employees")
      .map(response => response.json());
  }
}

App.Component.html

{{employeeData$ | async}}

Observable is said to be a stream of data that can change over time. I expected the data to start showing as soon as it begins streaming the employees, but in this case, my page remains blank for 30 seconds before all the employee data suddenly appears.

So, what's the advantage of using an observable? Couldn't I just load all the data into a local array and then display it on the HTML?

Is there a way to make the data display as soon as it receives the first employee, instead of making the user wait for 30 seconds?

I realize that in a real application, I should only fetch the number of employees that can be seen in the browser's view, and then load the next set of employees.

Answer №1

In the world of Angular, the HTTP Observable operates by yielding only when the entire stream is complete - in other words, when all the data has been successfully transferred. This means it will only yield once, providing a single value.

It seems that the issue with the BE (Back-end) is not too severe, as the 30-second delay could be attributed to the sheer size of the JSON being processed. The serialization and deserialization of such a large file can consume a significant amount of time, especially when coupled with downloading 50 Megs over the network.

One potential solution is to create a custom "progressive" HTTP call that can return a stream of employees every time a new chunk of data is received. This can be achieved using low-level XMLHttpRequest or by exploring libraries that offer this functionality.

Attempting to parse an incomplete JSON in order to retrieve "the data received so far" is not advisable. In such cases, it may be worth considering multiple HTTP requests with pagination, allowing you to fetch the necessary employees in batches.

Here's an example code snippet that illustrates this approach:

function getEmployeeStream():Rx.Observable<Employee[]> {
    return Rx.Observable.interval(100)
        .concatMap(
            i => getEmployees(i)
        )
        .takeUntil(
            employees => employees.length === 0
        )
        .scan(
            (allEmployees, receivedEmployees) => allEmployees.concat(receivedEmployees),
            []
        );
}

function getEmployees(page:number):Rx.Observable<Employee[]> {
    return this.http(...)
        .map(data => parseEmployees(data));
}

This code snippet generates a new event every 100ms, converts each event into a paginated call to the server, continues fetching employees as long as data is received, and combines them into a single array for use with the async pipe.

If you need to speed up the data retrieval process by making concurrent calls, you can replace concatMap with mergeMap and adjust the concurrent parameter accordingly. However, you may need to address the issue of incomplete calls being discarded due to the termination condition employees.length === 0. One workaround could be using takeUntil to wait for a set number of empty employee responses corresponding to the maximum allowable concurrent calls, ensuring completion of all pending responses.

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

What is the best way to access data from a local JSON file in Gatsby when using TypeScript and GraphQL?

I'm updating my former gatsby site using TypeScript. I encountered an issue while trying to retrieve data from a local JSON file: There appears to be an error in your GraphQL query: Cannot find field "allNavigationLinksJson" on type "Q ...

Unable to render ASP.NET Core 2 WebAPI and Angular application on the webpage

Following a tutorial, I created an ASP.NET Core 2 Web API. The API functions properly when accessed through the browser at: https://localhost;44313/api/liveconsole To design the Angular UI for my web API, I referred to another tutorial. After multiple at ...

Angular 2 Dropdown Multiselect Plugin - Fully Customize Width to 100%

Currently working on integrating the angular-2-dropdown-multiselect component: https://www.npmjs.com/package/angular-2-dropdown-multiselect The component functions correctly, but I am looking to adjust its width to fit the container... I believe simply ...

Creating a key-constrained type in Typescript for object literals with automatically deduced number values

Suppose we have an object literal defined as: export const SOURCE = { UNKNOWN: 'Unknown', WEB: 'Web', MOBILE: 'Mobile', ... } as const; and export const OTHER_SOURCE = { UNKNOWN: 0, WEB: 1, MOBILE: ...

Angular 5 Material Datepicker: A Sleek and Efficient Way to

I want the Angular Material Datepicker to remain open by default when the page is loaded, appearing within a section without needing to be triggered by an input field click. Currently, I am using a Datepicker that necessitates clicking on an input field. ...

Adding a separator for thousands on data labels in ng2-charts

Take a look at this demonstration: http://embed.plnkr.co/7fGsiuRjcF0M0Ffeoml2/ If I modify the data to be: data: [2000, 3000, 4000, 8000, 12000, 12850] Can I add thousand separators to the dataset label? For example: 5,000 10,000 15,000 ...

Using Next.js, it is not possible to use absolute imports within SASS

Having trouble utilizing @/ imports within my scss files. The variables I need are stored in src/styles/_variables.scss Here is my tsconfig.json: { "compilerOptions": { "lib": ["dom", "dom.iterable", "esnext"], "baseUrl": ".", "allowJs": tr ...

Can Schema and Model/Entity Files be Decoupled in TypeORM?

Having experience with PHP (Laravel/Eloquent, Symfony/Doctrine), I am accustomed to ORMs not defining schema but making schema attributes accessible. In my previous work, I never had to use a "Model" file to manage schema as it was always handled through m ...

Angular 2 and beyond: delivering a unified global service instance for sub-modules

Exploring how to create a comprehensive service that can be accessed from submodules within an angular 2+ application is key. While the traditional component hierarchy setup works well for this, understanding the process when dealing with multiple modules ...

Eliminate duplicate dropdown options in Angular 2 using a filter function

Is there a way to filter reporting results in an Angular 2 dropdown list? I am currently attempting to do so within the *ngFor template but haven't had any success. I will also try using a custom pipe. The data is coming from a JSON array. Specificall ...

Error Message: "Unable to access property 'proposta_usuario' of undefined in Angular 2 Data Binding"

I've been encountering some issues while trying to bind data from an input in Angular 2. Below is the HTML code snippet: <input type="text" class="animated bounceIn input-proposta" placeholder="Enter your proposal" [(ngModel)]="propo ...

Exploring the application of styles within the shadow DOM

I'm experimenting with applying styles to the shadow DOM. Consider the following example: const element = document.getElementById("bar"); const shadowRoot = element.attachShadow({ mode: "open" }); const greeting = document.createElement("p"); gree ...

Swapping elements with drag and drop in Angular 7

I'm experimenting with the new Angular 7 CDK Drag and drop feature to rearrange a list of items. However, I haven't been able to find an option to swap elements - most of the examples focus on sorting elements instead. Check out this example on ...

"Here's how you can mark an option as selected in Angular, either from the component or the HTML file

When it comes to my form, I have a select menu that sends data to an SQL database and then fetches it back when it is called for editing. The value being edited should be displayed in the select menu option as selected. Here's a peek at my code: < ...

The specified 'contactId' property cannot be found within the data type of 'any[]'

I am attempting to filter an array of objects named 'notes'. However, when I attempt this, I encounter the following error: Property 'contactId' does not exist on type 'any[]'. notes: Array < any > [] = []; currentNot ...

Navigating product search in your Ionic Ecommerce App

Currently, I am working on developing an Ionic Ecommerce App with a large number of products that need to be displayed. However, I am facing a challenge when it comes to implementing the search functionality for these products within the Ionic App. After c ...

Angular selects the initial three arrays out of an array

In my code, I have a collection of arrays that are nested within another array. My task is to extract the first three arrays from this collection. For instance, consider the following example: [{[1]},{[2]},{[3]},{[4]}] I apologize for not presenting a p ...

Converting a stringified array object to an object using Expressjs

When working with Angular, I am sending stringified data using FormData. Here is an example: this.formData.append('data', JSON.stringify(this.collections)) Now my challenge is converting this string back to an object in my Express backend. The d ...

Struggling to Enforce Restricted Imports in TypeScript Project Even After Setting baseUrl and resolve Configuration

I am facing challenges enforcing restricted imports in my TypeScript project using ESLint. The configuration seems to be causing issues for me. I have configured the baseUrl in my tsconfig.json file as "src" and attempted to use modules in my ESLint setup ...

Tips for refreshing the 'state' of an Angular Router component

I'm facing an issue with passing data between pages using Angular routing. Everything works as expected when navigating to the "next" page for the first time. However, upon returning to the home page and selecting a different item, the Router's s ...