typescript fetch and load JSON data from a URL into arrays

Currently, I am receiving JSON data from a URL. The data is structured in the following way:

[
  {"id":1,"symbol":"SP-500","date":"1927-12-30T07:00:00.000+00:00","open":17.66,"high":17.66,"low":17.66,"close":17.66,"volume":0},
  {"id":2,"symbol":"SP-500","date":"1928-01-03T07:00:00.000+00:00","open":17.76,"high":17.76,"low":17.76,"close":17.76,"volume":0}
]

The code snippet responsible for fetching this data resides in quote.service.ts and is structured as follows:

  getQuotesList(): Observable<any> {
    return this.http.get(`${this.baseUrl}`);
  }

The full class, including dependencies and methods, can be found below:

        import { Injectable } from '@angular/core';
        import { HttpClient } from '@angular/common/http';
        import { Observable, Subject } from 'rxjs';
        import { of } from 'rxjs';
        import 'rxjs/add/operator/map'
        import 'rxjs/operator/filter';
        import { Quote } from "./quote";
        
        @Injectable({
          providedIn: 'root'
        })
        export class QuoteService {
        
          private baseUrl = 'http://localhost:8080/springboot-crud-rest/api/v1/quotes';
        
          constructor(private http: HttpClient) { }
        
          // Additional methods for CRUD operations
        
          getQuotesList(): Observable<any> {
            // Transformation of data for charting purposes
          }
        }

After fetching and loading the data into an array in quote-list.component.ts, the data is presented in a tabular format using the code snippet below:

<tr *ngFor="let quote of quotes | async">
  <td>{{quote.symbol}}</td>
  <td>{{quote.date}}</td>
  <td>{{quote.open}}</td>
  <td>{{quote.high}}</td>
  <td>{{quote.low}}</td>
  <td>{{quote.close}}</td>
  <td>{{quote.volume}}</td>
  <td><button (click)="deleteQuote(quote.id)" class="btn btn-danger">Delete</button>
      <button (click)="quoteDetails(quote.id)" class="btn btn-info" style="margin-left: 10px">Details</button>
  </td>
</tr>

The next step is to extract and organize the values into separate arrays for each data type (such as dates and open prices) to facilitate plotting in a JavaScript charting program. Various attempts have been made to achieve this, but certain errors have been encountered. Assistance and guidance on resolving these issues are greatly appreciated!

UPDATE: The code has been successfully hosted on a Linux server. To access the live data, please visit the following URL in your browser: 167.172.141.34:8080/springboot-crud-rest/api/v1/quotes

Answer №1

There are a couple of components to consider in this query. Firstly, you need to figure out how to transform the JSON data into the desired array format. Additionally, handling Observables which encapsulate the actual data you wish to retrieve is another challenge.

For the first aspect, below is a snippet of code that demonstrates how to convert the data format:

const quotes = [
  {"id":1,"symbol":"SP-500","date":"1927-12-30T07:00:00.000+00:00","open":17.66,"high":17.66,"low":17.66,"close":17.66,"volume":0},
  {"id":2,"symbol":"SP-500","date":"1928-01-03T07:00:00.000+00:00","open":17.76,"high":17.76,"low":17.76,"close":17.76,"volume":0}
] 

const chartData = Object.assign({}, 
  ...Object.keys(quotes[0]).map(key => ({
    [key]: quotes.map(quote => quote[key])
  })))

console.log(chartData)

To extract data from the observable, you simply need to subscribe to it. I have included the conversion code from earlier as a standalone function, but you could also incorporate it inline:

getQuotesList() {
  const quotes = this.http.get(`${this.baseUrl}`)
  quotes.subscribe(quotes => this.toChart(quotes))
  return quotes
}

toChart (quotes) {
  const chartData = Object.assign({}, 
      ...Object.keys(quotes[0]).map(key => ({
          [key]: quotes.map(quote => quote[key])
      })))
  console.log(chartData)
}

Answer №2

Utilizing mapping is an effective strategy

var arr=[
  {"id":1,"symbol":"SP-500","date":"1927-12-30T07:00:00.000+00:00","open":17.66,"high":17.66,"low":17.66,"close":17.66,"volume":0},
  {"id":2,"symbol":"SP-500","date":"1928-01-03T07:00:00.000+00:00","open":17.76,"high":17.76,"low":17.76,"close":17.76,"volume":0}
]



Object.keys(arr[0]).forEach(el=>{
  let arrray= (el=="date") ? arr.map(ele=> ele[el].substring(0,10)) : arr.map(ele=>ele[el]);
  console.log(el,':', arrray);
  // implement your custom logic here
})

Subscribe for updates

return this.http.get(`${this.baseUrl}`).subscribe(arr=>{
   Object.keys(arr[0]).forEach(el=>{
      let arrray= (el=="date") ? arr.map(ele=> ele[el].substring(0,10)) : 
      arr.map(ele=>ele[el]);
      console.log(el,':', arrray);
      // implement your specific logic here
   })
});

Answer №3

The correct way to handle the resulting array from the subscribe method is crucial. Inside the callback function of subscribe, you will receive an actual array, allowing you to use your original approach with the .map method that was ineffective on the observer object in your first attempt.

fetchQuotes(): Observable<any> {
  let quotes = this.http.get<Quote[]>(`${this.baseUrl}`);
  quotes.subscribe((arr: Quote[]) => {
    const opens = arr.map(quote => quote.open)
    console.log(opens); // [17.66,17.76]

    const dates = arr.map(quote => quote.date.split("T")[0])
    console.log(dates); // [1927-12-30,1928-01-03]
  )}
  return quotes;
}

Answer №4

This code has a distinct odor... I firmly believe that the QuoteService method titled "getQuotesList" should have a singular purpose: to return an Observable just like you initially did.

In your component, I suggest storing the quote observable and creating a new observable using a switchMap operator with reduce logic inside.

For a potential solution, please refer to this stackblitz link: https://stackblitz.com/edit/rxjs-uurnuv?file=index.ts

Cheers!

Answer №5

An issue has been identified in the getQuotesList() function.

import { of, Observable } from 'rxjs'; 
import { map } from 'rxjs/operators';

const data = [
  {"id":1,"symbol":"SP-500","date":"1927-12-30T07:00:00.000+00:00","open":17.66,"high":17.66,"low":17.66,"close":17.66,"volume":0},
  {"id":2,"symbol":"SP-500","date":"1928-01-03T07:00:00.000+00:00","open":17.76,"high":17.76,"low":17.76,"close":17.76,"volume":0}
];

function getQuotesList(): Observable<[string[], string[]]> {
  // update to fetch data from this.http.get(this.baseUrl) instead of using of(data)
  return of(data).pipe(
    map((quotes) => {
      return quotes.reduce((acc, curr) => {
        acc[0].push(curr.date.substr(0, 10));
        acc[1].push(curr.open);
        return acc;
      }, [[], []]);
    }),
  )
}

getQuotesList().subscribe(x => console.log(x));

https://stackblitz.com/edit/rxjs-j8ptal?file=index.ts

UPDATE:

The complete class definition for your service is as follows:

import { Injectable } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { Observable, Subject, of } from "rxjs";
import { map } from 'rxjs/operators';
import "rxjs/add/operator/map";
import "rxjs/operator/filter";
import { Quote } from "./quote";

@Injectable({
  providedIn: "root"
})
export class QuoteService {
  private baseUrl = "http://localhost:8080/springboot-crud-rest/api/v1/quotes";

  constructor(private http: HttpClient) {}

  getQuote(id: number): Observable<any> {
    return this.http.get(`${this.baseUrl}/${id}`);
  }

  createQuote(quote: Object): Observable<Object> {
    return this.http.post(`${this.baseUrl}`, quote);
  }

  updateQuote(id: number, value: any): Observable<Object> {
    return this.http.put(`${this.baseUrl}/${id}`, value);
  }

  deleteQuote(id: number): Observable<any> {
    return this.http.delete(`${this.baseUrl}/${id}`, { responseType: "text" });
  }

  getQuotesList(): Observable<[string[], string[]]> {
    // replace of(data) with this.http.get(this.baseUrl)
    return this.http.get<Quote[]>(this.baseUrl).pipe(
      map(quotes => {
        return quotes.reduce(
          (acc, curr) => {
            acc[0].push(curr.date.substr(0, 10));
            acc[1].push(curr.open);
            return acc;
          },
          [[], []]
        );
      })
    );
  }
}

Answer №6

I strive to comprehend your desires.

  1. Your aim is to dissect json data into structured data of a specific type.
  2. You intend to consolidate data into array values.

Is that correct?

Allow me to provide you with some code.

interface Quote {
  id: number;
  symbol: string;
  date: string;
  open: number;
  high: number;
  low: number;
  close: number;
  volume: number;
}

const jsonList = [{
    "id": 1,
    "symbol": "SP-500",
    "date": "1927-12-30T07:00:00.000+00:00",
    "open": 17.66,
    "high": 17.66,
    "low": 17.66,
    "close": 17.66,
    "volume": 0
  },
  {
    "id": 2,
    "symbol": "SP-600",
    "date": "1928-01-03T07:00:00.000+00:00",
    "open": 17.76,
    "high": 17.76,
    "low": 17.76,
    "close": 17.76,
    "volume": 0
  }
]


function jsonParse < T = any > (json: any): T | null {
  try {
    return JSON.parse(JSON.stringify(json));
  } catch (error) {
    console.error('ERROR')
    return null;
  }
}

function aggregate < T = any > (dataList: T[]) {
  const aggregation = dataList.reduce < T[keyof T][][] > ((acc, data) => {
    Object.values(data).forEach((value: T[keyof T], index: number) => {
      if (Array.isArray(acc[index])) {
        acc[index].push(value);
        return acc;
      }
      acc[index] = [value]
      return acc;
    })
    return acc;
  }, []);

  return aggregation;
}

const quotes = jsonParse < Quote[] > (jsonList);
if (quotes) {
  const aggregationQuotes = aggregate < Quote > (quotes);
  console.log('quotes', quotes)
  console.log('aggregationQuotes', aggregationQuotes)
}

Answer №7

After some troubleshooting, I was able to successfully compile my code by following these steps:

npm install --save rxjs-compat

Next, I included the following import statement:

import { map } from 'rxjs/operators';

Finally, I wrote the code below to achieve an array of "open" values:

  getQuotesList(): Observable<any> {
    let quotes = this.http.get(`${this.baseUrl}`);
    let opens = quotes.pipe(map(theOpen => open));
    console.log(opens);
    return quotes;
  }

Unfortunately, the console.log(opens) does not display any output, which is an issue that needs further investigation.

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

Exploring the power of TypeScript for authenticating sessions with NextJS

Utilizing next-auth's getSession function in API routes looks something like this for me: const mySession = await getSession({ req }); I have confirmed that the type of the mySession is outlined as follows: type SessionType = { user: { email: s ...

What is the best way to enable external access to a class component method in React and Typescript?

I am currently working on a component library that compiles to umd and is accessible via the window object. However, I need to find a way to call a class component's methods from outside the class. The methods in my classes are private right now, but ...

Karma Unit test: Issue with accessing the 'length' property of an undefined value has been encountered

While running karma unit tests, I encountered a similar issue and here is what I found: One of my unit tests was writing data to a json file, resulting in the following error: ERROR in TypeError: Cannot read property 'length' of undefined a ...

Error message in Visual Studio 2017: Identical name 'URLs' declared twice in

In our Visual Studio 2017 project, we have multiple TypeScript files that define a URLs class. Each file contains different implementations of the class to change site URLs based on the specific use case: customer/urls.ts namespace Portal { export cl ...

Combining Pixie Image Editor with Ionic 3.X

I am attempting to connect Pixie Image Editor with Ionix 3.X. After trying to install it via npm install "Path of the source folder provided in the package" The installation message reads "pixie": "file:pixie" in package.json, but I encounter an error wh ...

Example of Using Bluebird in a Chain of Catch and Then Functions

I am struggling to understand how promises work in my code flow setup. I want to create a register function with multiple steps, but I'm unsure of what is achievable and what is not. Imagine I have a register function where I need to: register a u ...

Creating type definitions for TypeScript (ts) involves defining the shape and

Having trouble using a library installed in node_modules/ within a typescript app? Here's a quick hack for you. Create a folder named after the module in typings/modules and add an index.d.ts file inside with the following content: declare module "li ...

Unable to post links on Facebook when using Angular 7

Is it possible to share a URL on Facebook using Angular 7 without server-side rendering like Angular Universal or prerender? I attempted to update meta tags for Facebook share during the click function, but it did not work. What is the most effective way t ...

How can one correctly cast or convert an array of objects to the interface that extends the objects' parent interface in Typescript?

Question: How can I optimize the usage of method sendItemIdsOverBroadcastChannel to reduce message size? interface IItemId { id: number; classId: number; } interface IItem extends IItemId { longString: string; anotherLongString: string } inte ...

Angular unit tests do not trigger the QueryList.changes.subscribe() listener

I need to create popup containers based on the number of items received. The component works fine in dev and prod environments, but fails in unit tests because querylist.changes does not emit. As a workaround, I have to manually call querylist.notifyChange ...

What is the best way to obtain user-inputted data from a dynamic input table with dynamically added rows?

I am struggling to fetch the user-entered data from a dynamic inputs table. Each time a new row is added dynamically to the table, I have to create a new array in the component.ts file to retrieve the data using Two-way data binding. Below is the HTML cod ...

Can you explain the significance of triple brackets (e.g. {{{ content }}}) in the context of Javascript/Typescript?

As I delve into the code of a fresh project in which I hope to contribute, I have come across numerous methods defined with triple brackets, like so: deinitialize() {{{ this.destroyed = true; $(window).off("resize", this.resize as () => void); ...

Angular + Ionic 4 - Converting String Interpolation to JSON String

I am working with a JSON object that looks like this: { "commands": [ { "command":"begin ${{password}}", "name":"Initialization", "description":"Send SMS begin+password" } ] } How can I dynamically pass data to ${{password}} ...

Effective methods for transmitting reactive form control between child and parent components in Angular 2

I am working with a nested reactive form structure and I have the following setup: Parent HTML Code <form> <child-component></child-component> <button mat-raised-button color="primary">Save</button> </form> Child HT ...

Type inference error in TypeScript occurs within a conditional statement when the condition relies on the output of a function call rather than a boolean expression

In my TypeScript code, I have a Linked List class that is working perfectly. The class includes a Node type and functions to add items to the list. type ListItem = number | string | object; class Node { private value: ListItem; private next: Node | nu ...

Investigating the Angular signals that triggered the effect

Is there a way to determine which Angular signal triggered an effect? I have two signals and one effect in a component. One signal is used to start a timer function within a service, while the other signal reacts to changing conditions in the timer functio ...

Electron does not have the capability to utilize Google's Speech to Text engine

I am trying to connect my microphone with the Google Speech to Text engine. I came across this page and copied the code into my renderer.ts file, uncommented the lines with const, but when I run it, I encounter an error at line 7 (const client = new speech ...

Click on a kendo-chip in Angular to copy its content

Can someone assist me in copying the content within a Kendo Chip when clicked in an Angular application? Your help is greatly appreciated. View image here ...

Automating the scrolling function in Angular 2 to automatically navigate to the bottom of the page whenever a message is sent or opened

In my message conversation section, I want to ensure that the scroll is always at the bottom. When the page is reopened, the last message should be displayed first. HTML: <ul> <li *ngFor="let reply of message_show.messages"> ...

Angular design pattern: organizing rows according to the month

I currently possess the following items: { "pk": 33, "name": "EVENT 634", "start_date": "2022-05-11T00:00:00", "end_date": "2022-05-14T00:00:00" }, { "pk": ...