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

Create an entity with a field that holds a value type based on the value of another key field

Essentially, I am looking to create a customized "Pair" data type For example: type Pair<T extends Record<string, string | number>, K extends keyof T> = { field: K, value: T[K] } So, if we have: type Rabbit = { name: string, a ...

Integrating Laravel 5.6 with Angular 6 for seamless functionality

For my project, I am considering using Laravel as the backend and Angular as the frontend. There are two methods that I can use to integrate these frameworks: 1) I could integrate both frameworks by utilizing an API service, or 2) I could opt for a monol ...

Querying data elements using Graphql mutations: a step-by-step guide

const MUTATION_QUERY = gql` mutation MUTATION_QUERY( $name: bigint! ) { insert_name( objects: { name: $name } ) { returning { id name } } } `; const [onClick, { error, data }] = useMut ...

Resolve a 404 error caused by missing parameters in a GET request on a CherryPy server

My current project involves creating a webpage using CherryPy for server-side scripting, along with HTML, CSS, and jQuery for the client-side. I am also integrating a mySQL database into the system. One key feature of the site is a signup form where users ...

Customizing the hover behavior of a div element without causing displacement of surrounding elements

I am facing an issue where the descriptions in my list of 100 items are longer than the width of the div, causing the text to be cut off. I want to display the full description on hover without affecting the layout of other items. Currently, when I hover o ...

Decoding an array of intricate JSON entities using MOXy JAXB 2.5.1

In my Apache CFX project, I am using MOXy JAXB to unmarshal JSON/XML. One particular request is causing me some trouble: {"CC.ConsumerPersistAppDataRequest" : { "SessionId" : "42", "AppData" : [ {"AppDatum" : { "TimeStamp" : 1384548486 ...

Unable to retrieve Objects from JSON

Here is a JSON object I received: [{"model": "pricing.cashflow", "pk": 1, "fields": {"value": 4.0, "date": "2016-09-09"}}, {"model": "pricing.cashflow", "pk": 2, "fields": {"value": 3.0, "date": "2016-09-01"}}, {"model": "pricing.cashflow", "pk": 3, "fiel ...

What is the best way to change the number 123456789 to look like 123***789 using either typescript or

Is there a way to convert this scenario? I am working on a project where the userID needs to be displayed in a specific format. The first 3 characters/numbers and last 3 characters/numbers should be visible, while the middle part should be replaced with ...

Resolving redundancy in Typescript Material-UI Table codebases

Apologies for the ambiguous question title, it was difficult to come up with something more specific. I am currently exploring the Typescript implementation of Material-UI tables, specifically focusing on the table section titled "Sorting and selecting". ...

Setting a Validator for a custom form control in Angular: A step-by-step guide

I need to apply validators to a specific control in formGroup from outside of a custom control component: <form [formGroup]="fg"> <custom-control formControlName="custom"> </custom-control> </form> this. ...

Create metadata.json and ngsummary.json files in Angular 2

Hello fellow Angular 2 developers, I've been running into some trouble trying to find comprehensive documentation on the angular 2 compiler (ngc). Here's my situation: I have a directory that contains an Angular 2 logging library with a main fi ...

Why ngIf in Angular Ionic doesn't correctly compare arrays from parent when using the 'includes' method?

I have implemented a feature where users can select their interests through a dialog. When a user clicks on a chip, the following method is triggered: handleClick(tag){ let found = false; let index = -1; // tslint:disable-next-line:prefer-for-of for (let ...

Using Typescript to create a Checkbox Grid that displays pipe-delimited values and implements a custom validation rule

I am currently working with a checkbox grid that contains pairs of AccountIds (consisting of x number of digits) and file names separated by a pipe delimiter. The file names are structured to always begin with either PRC or FE followed by a varying combin ...

Encountering a type conversion error when trying to parse JSON data in C

When attempting to populate a vector of json data type with json objects, I encountered an error when loading this vector into a json response. The following method was attempted to push json objects into the vector of json data type: std::vector<json_ ...

mat-slider: experiencing delay in updating while dragging it

Incorporating @angular/material in my Angular 5 application has been quite the journey. The specific version of Angular Material that I have implemented is 5.0.2, along with @angular/animations 5.1.2. My usage of the slider component is rather straightfor ...

Transform JSON data into a C# class with dual Dictionary attributes

Currently, I am in the process of creating an app using Xamarin and I have a straightforward JSON file consisting of objects that I want to deserialize all at once into my C# Class within my domain. (I am relying on the Newtonsoft Json.NET Framework) Each ...

What is the reason the server is not receiving the cookie?

I am currently running a nodejs express application on a server with two endpoints: POST /session - used to send back the cookie GET /resource - used to check if the cookie is sent back, returning 401 not found if it's not On the frontend, hosted on ...

Ways to adjust the color dynamics of a mat-slider

I am looking to dynamically change the color of a mat-slider. In my app, users have the ability to select any color from a color palette, and I want to display that selected color as the slider color. While I know you can add custom color names in the col ...

Is it possible to use the ""get" prefix for a function in Spring Boot?

I am facing an issue with my Mcq class that is linked to a MongoRepository. I am trying to retrieve an instance of my Mcq after applying certain changes such as shuffling answers and drawing questions. I have defined a function called "myMcq.getInstance()" ...

Using Formik: When the initial value is changed, the props.value will be updated

After the initial props are updated, it is important to also update the values in the forms accordingly. export default withFormik({ mapPropsToValues: (props: Props) => { return ( { id: props.initialData.id, ...