Tips for extracting information from a TypeScript JSON document

Hey there, I'm currently having trouble understanding how to retrieve data from a JSON file.

environment.ts:

    export const environment = {
  production: false,
  urlListBooks: "/assets/list-books.json",
  urlGetBooks: "/assets/edit-book.json?:id",
  urlGetTags: "/assets/edit-book.json?:tags",
  urlPostBooks: "/assets/edit-book.json",
  urlListTags: "/assets/list-tags.json",
  urlPostTags: "/assets/edit-tag.json"
};

edit-book.json:

"book":{
    "id": 1,
    "title": "The Shining",
    "authorId": 1,
    "tags": [{"name":"new"}, {"name":"test"}]
},
"authors":[
    {
        "id": 1,
        "prename": "Stephen",
        "surname": "King"
    },
    {
        "id": 3,
        "prename": "Algernon",
        "surname": "Blackwood"
    },
    {
        "id": 4,
        "prename": "Edgar Allan",
        "surname": "Poe"
    },
    {
        "id": 5,
        "prename": "Howard Phillips",
        "surname": "Lovecraft"
    }
],
"tags":[
    {
        "name": "new"
    },
    {
        "name": "Horror"
    },
    {
        "name": "Romance"
    }
]

}

service:

  getBookTags(n: String) Observable<Tag[]>{
    return this.http.get<Tag[]>(environment.urlGetTags.)
  }

I want the function getBookTags(n: String) to return the tags array of the book with the title n as defined in edit-book.json (for example, "tags": [{"name":"new"}, {"name":"Horror"}]) so that I can use it later to check which tags a book has and select them.

Your assistance on this matter would be greatly appreciated :)

Answer №1

Alright, I believe I have solved the issue you were facing. Let me walk you through my thought process so you can understand the objective. You can find my solution by following this link: https://codesandbox.io/s/thirsty-minsky-g6959f?file=/assets/edit-book.json:0-752

First off, the JSON data provided doesn't seem quite right. It shows multiple authors but only one "book". I assume you actually want multiple books instead. Also, make sure to wrap it within curly braces as demonstrated below:

{
  "books": [
    {
      "id": 1,
      "title": "The Shining",
      "authorId": 1,
      "tags": [{ "name": "new" }, { "name": "test" }]
    },
    {
      "id": 2,
      "title": "The Wendigo",
      "authorId": 2,
      "tags": [{ "name": "Horror" }]
    }
  ],
  "authors": [
    {
      "id": 1,
      "prename": "Stephen",
      "surname": "King"
    },
    {
      "id": 3,
      "prename": "Algernon",
      "surname": "Blackwood"
    },
    {
      "id": 4,
      "prename": "Edgar Allan",
      "surname": "Poe"
    },
    {
      "id": 5,
      "prename": "Howard Phillips",
      "surname": "Lovecraft"
    }
  ],
  "tags": [
    {
      "name": "new"
    },
    {
      "name": "Horror"
    },
    {
      "name": "Romance"
    }
  ]
}

Next, in your Typescript code, let's establish typings for the JSON data you'll be fetching. This will enhance readability, provide intellisense, and help catch errors beforehand. Define the properties of the JSON like so:

type Tag = {
  name: string;
};

type Book = {
  id: number;
  title: string;
  authorId: number;
  tags: Tag[];
};

type Author = {
  id: number;
  prename: string;
  surname: string;
};

type BookData = {
  books: Book[];
  authors: Author[];
  tags: Tag[];
};

In essence, we have bookdata comprised of books, authors, and tags. Each entity has its own set of properties defined under their respective types.

Now onto the actual implementation, we'll utilize the fetch API to retrieve the JSON data from the specified URL.

async function getBookTags(n: string): Promise<Book[]> {
  return fetch(url)
    .then<BookData>((res) => res.json())
    .then((data) => data.books)
    .then((books) => books.filter((b) => doesBookHaveTag(b, n)));
}

The initial step involves fetching the data via the API, resulting in a promise. Upon resolution, we parse the response into JSON format. Subsequently, after another promise resolution, we filter out books based on matching tags.

The helper function doesBookHaveTag is simply designed to determine if a book contains a specific tag:

function doesBookHaveTag(book: Book, n: string): boolean {
  // check if book has at least one tag matching n
  return book.tags.some((t) => t.name.toLowerCase() === n.toLowerCase());
}

If promises are unclear, consider watching tutorials to grasp the concept. Essentially, the browser sends an http request which resolves into executing functions specified within .then when there's availability. To call your async function and log all books tagged as "horror", execute the following:

getBookTags("horror").then(console.log); // displays the relevant book

This should elucidate how to retrieve data, handle its promise, and define your responses. While Angular specifics may vary (I'm more proficient with React), the core principles discussed apply universally to Javascript/Typescript coding.

[endnote]: When referring to a function in .then, it implies passing a function inside the .then method. For instance, data => data.books signifies a function, equivalent to:

function(data: BookData): Book[] {
    return data.books
}

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

Angular Unit Test - Overcoming CORS Issue During XMLHttpRequest Access

I am currently facing a CORS problem within my Angular test spec file. I am unsure of how to resolve this issue, which occurs in the second line. beforeEach(() => { fixture = TestBed.createComponent(FhcComponent); //THIS IS WHERE THE ISSUE ARISES ...

Error in Typescript Observable when using .startWith([])

I encountered the TypeScript error below: Error:(34, 20) TS2345: Argument of type 'undefined[]' is not assignable to parameter of type 'number | Scheduler'. Type 'undefined[]' is not assignable to type 'Scheduler& ...

Exploring ways to use TypeScript to export a Mongoose model?

There's a module I need to export in order to avoid the error "OverwriteModelError: Cannot overwrite Task model once compiled". I've tried various solutions but none seem to work. The problem lies in the last line (export default models...) impo ...

Handling Movement Events in PrimeNG PickList ComponentsExplore the onMove and onMoveAll event

I am currently utilizing PrimeNG PickList version 5.0.0-rc0 in my Angular 5 project. An issue I am encountering is that the functions onMoveToTarget and onMoveAllToTarget are being triggered simultaneously, which, in my opinion, should not happen. The Pick ...

Moving SVG Module

My goal is to create a custom component that can dynamically load and display the content of an SVG file in its template. So far, I have attempted the following approach: icon.component.ts ... @Component({ selector: 'app-icon', templa ...

Triggering blur event manually in Ionic 3

Is there a way to manually trigger the blur event on an ion-input element? The ideal scenario would be with an ionic-native method, but any javascript-based workaround will suffice. My current configuration: Ionic: ionic (Ionic CLI) : 4.0.1 (/User ...

Generating JSON files using structure formatting for pigs

I have a task involving formatting address data to create a JSON file. Currently, my data is in the following format: Y: { name: chararray, { ( address: { ( street: chararray,city: chararray,state: chararray,zip: chararray ) } ) } } The data I have looks ...

Enhance user interaction in Angular 13 by animating a selected element using just one animation block

I am currently working on a one-page website project to enhance my Angular skills, and I'm facing a challenge with animating multiple DOM elements using a single animation. Defining the animation for each element individually seems like a cumbersome a ...

Encountering difficulties in transmitting ngModel across multiple layers

I'm encountering a problem when trying to pass ngModel through the second child component. It seems that as soon as I do that, it stops working. In order to pass the ngModel, I implemented this abstract class: export abstract class AbstractValueAcces ...

What are the benefits of using default ES module properties for exporting/importing compared to named module properties?

Currently studying the Material UI documentation, I came across this statement: It is noted in the example above that we used: import RaisedButton from 'material-ui/RaisedButton'; instead of import {RaisedButton} from 'material-ui&apo ...

Having trouble modifying the value of a textBox with ngModel and a directive

Having trouble trimming a text input and ending up with duplicate values New to Angular, seeking help in finding a solution View Code on StackBlitz ...

Reading JSON files from the www directory of an Android Phonegap application with AngularJS

I'm attempting to access a local JSON file within the www directory of my PhoneGap application. Unfortunately, I tried using the $resource service in Angular to load the file, but it was unsuccessful. $resource('/app/www/app/Commun/JSonFiles/: ...

Effective ways to decode Magento's JSON web services on an Android platform

Learning android for the first time and struggling to extract data from Magento webservices. Using ksoap2 library to fetch data from webservices. Here is the code snippet I utilized to retrieve data. In async task, web service is invoked to receive respon ...

How can nested dictionaries be created in Python from a JSON file with dotted notation?

Here is an example of a JSON file structure: { "x": 0.123456789, "x.y": 0.987654321, "x.z": 0.567890123 } Let's call this dictionary "data" I am looking to access the values in the following manner: if " ...

Ag-Grid is displaying a third column that is not present in my dataset

Recently, I've been working with Angular and incorporating the Ag-Grid into my project. My goal is to display a grid with two columns; however, upon implementation, an unexpected third separator appears as if there are three columns in total. Even w ...

Setting up OpenID configuration in angular-oauth2-oidc to bypass authentication for certain addresses

In my Angular project, I implemented OpenID authentication using the angular-oauth2-oidc project. However, I need to disable authentication for certain routes. To achieve this, I start the code flow in the main component and bootstrap it in the main modu ...

What could be the reason behind the malfunction of nativescript-phone on Android during plugin build?

I am encountering a particular build error while trying to deploy our NativeScript app on my Android Studio Emulator: > Failed to build plugin nativescript-phone : Error: spawn ./gradlew ENOENT Exception in thread "DisconnectableInputStream source ...

Issue encountered while managing login error messages: http://localhost:3000/auth/login net::ERR_ABORTED 405 (Method Not Allowed)

I am working on the /app/auth/login/route.ts file. import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs' import { cookies } from 'next/headers' import { NextResponse } from 'next/server' export async functi ...

How should we correctly import jquery.inputmask?

Struggling to import jquery.inputmask using webpack and TypeScript? Head over to this discussion at Issue #1115 : Here's how I configured things with jqlite: To import in your app, use the following code: import InputMask from 'inputmask&apos ...

Handling HTTP errors in Angular when receiving a JSON response

I'm struggling to resolve this issue and I've searched online with no luck. The problem lies in my post call implementation, which looks like this: return this.http.post(url, body, { headers: ConnectFunctions.getHeader() }).pipe( map(result =&g ...