0

I have a service set up with some static objects that I am using 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 runs another function which adds another array of data to it such as availableOperators and availableValues. Those too are just static json objects.

In my component, I have a function that is fetching this data by ID using lodash.

fetchVariableData(id, type) {

    let data = [];

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

    return data;

}

In my component HTML, I am running an ngFor using my function to fetch the results.

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

The issue here is that I am running into some async issues I believe. When I run this, I get an error that availableOperators is undefined. If I hardcode the operators into my fetchVariableData() function however, it works fine.

How can I handle this async issue where it appears that it is trying to use the availableOperators when it isn't ready?

This is all static JSON, no HTTP calls.

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]);
  }
}
10
  • It's not an async issue if its all static data and you're not dealing with any promises/observables, etc. Can you post the rest of the code for the component? Unless you defined it differently elsewhere, you're using a block-scoped variable to define 'variables' with the 'let' keyword. Then, in a different method (outside the block with different scope), you're trying to use 'this.variables' to access it. It has to be set as an instance property for the component for that to work. A variable defined with 'let' basically ceases to exist outside its original scope (method, in this case) Commented Aug 23, 2017 at 1:51
  • @diopside Hm, so the let variables is defined in my service file. In my component, within my ngOnInit, I am running this.variables = this._mserv.fetchRuleVariables(); In my component, I then access this.variables from my code mentioned via fetchVariableData(). Does this clear it up any more ? Commented Aug 23, 2017 at 1:55
  • What's your fetchOperators implementation? Commented Aug 23, 2017 at 2:02
  • 1
    @diopside sorry, I omitted the return by mistake in the original post. Commented Aug 23, 2017 at 2:05
  • 1
    I'd try to initialize variables: any = [] first, then do an *ngIf="variables.length" on its container. Out of curiosity, what do you get if you console.log(id, type) right after the function definition in fetchVariableData, i bet first time might be called without any valid value, therefore the find wont get anything and that's where the undefined comes. Commented Aug 23, 2017 at 2:19

1 Answer 1

1

Check the lifecycle of your component;

As explained here in the official guide your AddRuleComponent calls ngOnInit() to fetch and initialize the data for the component.

As stated in the docs, the order is constructor, ngOnChanges(), ngOnInit() and so on, so by the time ngOnInit() fetches the values, your component already checked if the properties has been initialized/mutated, that's why fetchVariableData() could be called with invalid params (happening from the ngOnChanges()) resulting in the undefined error because _.find(...) is not returning the variables object as you expect.

I'd try to initialize first:

variables: any = [];

and then do an *ngIf="variables.length" on the container, or move the initialization to the constructor.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.