Challenges in handling asynchronous data within static JSON objects in Angular2

I have a service set up with some static objects that are being utilized in my UI.

fetchRulesVariables()

fetchRuleVariables() {

    let variables = [

        {
            name: 'Credit Funding Type',
            id: 1,
            multiple: false,
            hasOperators: true,
            availableOperators: this.fetchOperators('inResults'),
            inputType: 'single',
            placeholder: 'Select a funding type',
            availableValues: this.fetchFundingInstraments()
        }, {
            name: 'Device Trust Score',
            id: 2,
            multiple: false,
            hasOperators: true,
            availableOperators: this.fetchOperators('gtltResults'),
            inputType: 'text',
            placeholder: 'Enter a value between 0 - 100',
            availableValues: ''
        }
    ]
 return variables;
}

This object calls another function that adds additional data arrays like availableOperators and availableValues. These values are also static JSON objects.

In my component, I am retrieving this data by ID using the lodash library.

fetchVariableData(id, type) {

    let data = [];

    switch (type) {
        case 'operators':
            data = _.find(this.variables, {id}).availableOperators;
            break;
    }

    return data;

}

In my component's HTML, I am using an ngFor directive to display the results fetched by my function.

<li *ngFor="let x of fetchVariableData(1, 'operators')"></li>

The problem arises from async issues. When attempting to run this code, I encounter an error stating that availableOperators is undefined. However, if I manually input the operators into my fetchVariableData() function, it works as expected.

How can I address this async issue where it seems like availableOperators is being accessed before it's ready?

All the data used here is static JSON, with no external HTTP requests taking place.

Edit1

Component Code:

export class AddRuleComponent implements OnInit {
    variables: any;

    ngOnInit() {
        this.loadVars();
        this.renderAddRuleForm();
    }


    loadVars() {
        this.outcomes = this._mserv.fetchOutcomeTypes();
        this.variables = this._mserv.fetchRuleVariables();
    }

    fetchVariableData(id, type) {

        let data: any;

        switch (type) {
            case 'operators':
                data = _.find(this.variables, {
                    id
                }).availableOperators;
                break;
        }
        return data;
    }

}

Service Code:

fetchRuleVariables() {

    let variables = [

        {
            name: 'Credit Funding Type',
            id: 1,
            multiple: false,
            hasOperators: true,
            availableOperators: this.fetchOperators('inResults'),
            inputType: 'single',
            placeholder: 'Select a funding type',
            availableValues: this.fetchFundingInstraments()
        }, {
            name: 'Device Trust Score',
            id: 2,
            multiple: false,
            hasOperators: true,
            availableOperators: this.fetchOperators('gtltResults'),
            inputType: 'text',
            placeholder: 'Enter a value between 0 - 100',
            availableValues: ''
        }
    ]
 return variables;
}

fetchOperators(type) {

    let operators = [];

    // Based on the set of operators we want
    switch (type) {

        // In Results
        case 'inResults':

            operators.push({
                name: 'In List',
                id: 1,
            }, {
                name: 'Not In List',
                id: 2,
            });

            break;

            // Greater than & Less than
        case 'gtltResults':

            operators.push({
                name: 'Greater Than <',
                id: 3,
            }, {
                name: 'Less Than >',
                id: 4,
            });

            break;

            // Is / is not
        case 'isisnot':

            operators.push({
                name: 'Is',
                id: 5,
            }, {
                name: 'Is Not',
                id: 6,
            });

            break;
    }

    return operators;
}

HTML Code:

 <select class="form-control input-sm" formControlName="operator" [attr.id]="'operator'+i">
   <option value="">Select an Operator</option>
   <option *ngFor="let o of fetchVariableData(1, 'operators') | values" value="{{ o.id }}">{{ o.name }}</option>
 </select>

Values Pipe:

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({ name: 'values',  pure: false })
export class ValuesPipe implements PipeTransform {
  transform(value: any, args: any[] = null): any {
    return Object.keys(value).map(key => value[key]);
  }
}

Answer №1

Examine the lifecycle of your component;

Referencing the official Angular guide, it is clarified that your AddRuleComponent invokes ngOnInit() to retrieve and set up the data for the component.

According to the documentation, the sequence includes constructor, ngOnChanges(), ngOnInit(), and so forth. By the time ngOnInit() retrieves the values, your component has already confirmed whether the properties have been initialized or altered. Consequently, calling fetchVariableData() with incorrect parameters (potentially triggered by ngOnChanges()) could lead to an undefined error because _.find(...) does not return the anticipated variables object.

I recommend initiating first:

variables: any = [];

and then utilizing *ngIf="variables.length" on the container, or relocating the initialization to the constructor.

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

Utilize Angular 10 to send a post request and subsequently trigger another request upon successfully completing the first

I am looking for a way to register a user on the backend and then sign them in sequentially. The register route will create the user, while the sign-in route will return a UserModel object if successful. If registration fails, an error will be returned f ...

Generating Graphql types for React using graphql-codegen when Apollo Server is in production mode: A step-by-step guide

Everything functions perfectly when backend mode is set to NODE_ENV: development, but in production mode I encounter an error with graphql-codegen: Error on local web server: Apollo Server does not allow GraphQL introspection, but the query contains _sc ...

Chaining Assignments in TypeScript

let a: { m?: string }; let b = a = {}; b.m = ''; // Property 'm' does not exist on type '{}'. let a: { m?: string } = {}; let b = a; b.m = ''; // It's OK Link to TypeScript Playground What occurs ...

Guide to Dynamically Including an Element in an Array using Typescript

Encountering a type error within the <RenderFormFields formFields={formFieldsData} /> component:- Types of property 'type' are not compatible. Type 'string' cannot be assigned to type '"select"'.ts(2322) Rende ...

What is the best way to extract data from an array of objects in a JSON response?

I am currently exploring the utilization of API's in React. Right now, I am developing a search input feature for country names using the Rest Countries API. The data is being pulled from . However, I am facing a challenge in handling this data as it ...

Managing numerous API requests in React Native

As I work on implementing a search field, I've encountered a challenge. Whenever a user enters text in the search field, a timer resets to 300 ms before an API call is sent to fetch autocomplete results. After receiving these results, the app then wai ...

Python has raised an error: The JSON data has extra content

I'm currently working on a project where I've created a simple login screen program. In this program, users are asked to create an account containing their name, age, city, and login information which is stored in a JSON document. I've succe ...

The functionality of the System JS map is not functioning properly

Despite the challenges I face with System.js, I find it to be a valuable tool that I prefer over alternatives. This is my current System.js configuration: System.config({ packages: { app: { format: 'register' ...

Deleting data in JSON format using Ruby on Rails involves utilizing the appropriate

I am attempting to remove a row from the table using JSON. Here is the delete button code: link_to('Delete', product, method: :delete, data: { confirm: 'Are you sure?' }, remote: true) In the controller: def destroy @product.de ...

Is it possible to incorporate an interface with a named function in TypeScript (function declaration)?

Just dipping my toes into Typescript and experimenting with interfaces for my functions: interface StringFunction { (arg1: string): string } I managed to associate this interface with a function by declaring it as a variable: let testFunction: Strin ...

What is the simplest method to customize or enhance Angular 5 directives with Angular-material?

In my Angular5 application, I am utilizing the angular-material library in some areas. However, I prefer to maintain a level of agnosticism in my markup when it comes to external libraries. Despite this, I attempted the following approach: import { Direc ...

Issue with merging JSON in Angular using RxJS

Seeking assistance with combining two JSON objects in an Angular application. JSON Object 1: { "level1": { "level2": { "level31": "Text 1", "level32": "Text 2", "leve ...

The Angular Material autocomplete panel does not disappear when autocomplete is hidden within a scrollable region

Having encountered a bug, I have raised an issue for it (https://github.com/angular/components/issues/20209). I am reaching out to inquire if there exists any workaround or solution known to anyone. You can observe the problem on this demonstration page h ...

Encountering issues when implementing any ng statement

Just recently, I completed the installation of node and npm on my Ubuntu system. Along with that, I also installed Angular CLI. However, upon trying to use the ng statement such as ng new test-project, I encountered the following error: ----Mg: -- watch ...

Error Message: ElectronJS - Attempted to access the 'join' property of an undefined variable

I am currently working on developing a tray-based application. However, I am encountering an error that reads: Uncaught TypeError: Cannot read property 'join' of undefined Can anyone guide me on how to resolve this issue? This is the content ...

Generate a dynamic HTML table using an array of objects

I have a dataset that I need to transform into an HTML table like the one shown in this image: Despite my attempts to write the code below, it seems that the rows are being appended in different positions. Is there another method to achieve the desired ta ...

Utilizing a Bootstrap Frontend to Connect with a Rails JSON-API

Forgive me if this sounds naive, but I'm unsure how to access the 'endpoints' from my current Rails JSON-API Server in my Bootstrap page. Do I need to place the Bootstrap page within the view folder of the API server? If so, how do I invoke ...

I encounter an error in my JavaScript function indicating that it is not defined

let element = document.querySelector("#value"); let buttons = document.querySelectorAll(".btn"); buttons.forEach(function (button) { button.addEventListener("click", function(event){ console.log(event.currentTarge ...

Verify the data type being returned in the response by utilizing Retrofit

While using Retrofit, I have carefully crafted all the POJOs and everything was functioning smoothly. The API is set up to provide the necessary data for the current date or future dates, but not for past dates. The response consists of a JSON object with ...

The contenteditable DIV function is experiencing issues with Angular's two-way binding feature in the Firefox browser

After making my div contenteditable and triggering ngx-popover on keyup to display search results based on searchText, I am in need of two-way binding along with content editability. However, I prefer using a div instead of an input element: <span> ...