The ngShow directive is being assessed prematurely

In my development project, I have an Angular component and controller set up in the following way:

export class MyController{

    static $inject = [MyService.serviceId];

    public elements: Array<string>;
    public errorReceived : boolean;

    private elementsService: MyService;

    constructor(private $elementsService: MyService) {
        this.errorReceived = false;
        this.elementsService= $elementsService;
    }

    public $onInit = () => {
        this.elements =  this.getElements();
        console.log("tiles: " + this.elements);
    }


    private getElements(): Array<string> {
        let result: Array<string> = [];
        this.elementsService.getElements().then((response) => {
            result = response.data;
            console.log(result);
        }).catch(() => {
            this.errorReceived = true;
        });
        console.log(result);
        return result;
    }
}

export class MyComponent implements ng.IComponentOptions {
    static  componentId = 'myId';

    controller = MyController;
    controllerAs = 'vm';

    templateUrl = $partial => $partial.getPath('site.html');
}

The implementation of MyService is as follows:

export class MyService {

    static serviceId = 'myService';

    private http: ng.IHttpService;

    constructor(private $http: ng.IHttpService) {
        this.http = $http;
    }

    public getElements(): ng.IPromise<{}> {
        return this.http.get('./rest/elements');
    }

}

An issue that has arisen is that the array 'elements' remains empty after the invocation of onInit(). Nonetheless, data has been received as the success function in getELements() logs the elements to the console.

In my template, I use the 'elements' array to determine whether to display a specific element. Here's how it's done:

<div>
    <elements ng-show="vm.elements.indexOf('A') != -1"></elements>
</div>

The challenge now is that 'vm.elements' initially holds an empty array, and only later does it receive the actual values. By then, the expression in the template has already been evaluated. What adjustments can be made to address this?

Answer №1

Your current approach doesn't seem to be effective. It's important to have a good understanding of how promises and asynchronous operations work in this programming language to accomplish your objective. The good news is that it's not too difficult to grasp.

The issue with your existing implementation lies in the fact that your init method immediately returns an empty array without waiting for the result of the service call. As a result, the property in your controller gets bound to an empty array again, which is not the desired outcome.

You might want to consider the following alternative solution:

export class MyController {
   elements: string[] = [];

   $onInit = () => {
     this.getElements()
       .then(elements => {
         this.elements = elements;
       });
  };

  getElements() {
    return this.elementsService
      .getElements()
      .then(response => response.data)
      .catch(() => {
        this.errorReceived = true;
      });
   } 
}

To improve readability, you can utilize async/await:

export class MyController {
   elements: string[] = [];

   $onInit = async () => {
     this.elements = await this.getElements();
   };

   async getElements() {
     try {
       const {data} = await this.elementsService.getElements();
       return data;
     } 
     catch {
       this.errorReceived = true;
     }
   } 
}

As shown above, this approach allows you to use standard try/catch syntax, demonstrating one of the advantages of async/await.

Another key point to remember is that your data services should unwrap the response, specifically the data property, and return it so that your controller does not need to handle the details of the HTTP service.

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

Is there a way to determine the most recent Typescript target compatibility for every Node version?

When using any version of Node, how can I identify the appropriate Typescript Compiler Option for target that offers the most functionality? I want to eliminate any guesswork. Specify the ECMAScript target version as: "ES3" (default), "ES5", "ES6"/"ES20 ...

Navigating with UI-Router within a single view for both viewing and editing purposes

I have been encountering an issue with changing states between the view page and edit page using UI-Router. Here are some of the things I have attempted: Controller: $stateProvider .state('showViewA', { views: { ...

What is the best way to retrieve the current height in VueJS using the Composition API?

I am utilizing a Ref to preserve the current height of the active element. My goal now is to transfer this height to the subsequent element that gets clicked on. <script lang="ts" setup> import { ref, reactive } from "vue"; defin ...

AngularJS radio button slider with ng-model and ng-checked functionality

I'm facing an issue where my ng-model is not getting updated when I cycle through radio button images using arrows instead of clicking on the image. How can I resolve this? HTML <div ng-repeat="contact in contacts" ng-show="showContactID == ...

Confidently set up a proxy that is recursively nested and strongly typed

I have a collection of objects where I store various content for a user interface. Here is an example: const copy = { header: { content: 'Page Header' }, main: { header: { content: 'Content Subheader' }, body ...

Identifying data types in arrays using TypeScript type predicates

My current approach involves a function that validates if a variable is an object and not null: function isRecord(input: any): input is Record<string, any> { return input !== null && typeof input === 'object'; } This type predica ...

Enhance React component props for a styled component element using TypeScript

Looking to enhance the properties of a React component in TypeScript to include standard HTML button attributes along with specific React features such as ref. My research suggests that React.HTMLProps is the ideal type for this purpose (since React.HTMLA ...

Troubleshooting angular radio input display issue caused by controller updates

When the page loads, my AngularJS controller.js initializes the scope model by fetching data from an AJAX response: services.InitializePage().then(function (response) { $scope.DataModel = response.data; Shortly after that, the model undergoes ...

What can TypeScript do with high-level type functions?

Take a look at the following pseudo-code attempting to define a higher-order type function with a function-typed parameter M<?>: type HigherOrderTypeFn<T, M<?>> = T extends (...) ? M<T> : never; The syntax M<?> is not va ...

Using @HostBinding based on the @Input() condition

I'm attempting to link the CSS class foo to my parent component by utilizing @HostBinding based on a condition I evaluate against a dynamic variable. However, I am struggling to get it to function as expected. Here are the different approaches I hav ...

How to style large numbers with AngularJS

I'm facing a challenge with large numbers in a table and I'm seeking a solution to format them, ideally as $13b, $10m... Has anyone encountered this issue before and discovered a customized filter or solution for it? Appreciate any help! ...

The addition operator is not compatible with the given types

Hello, I am currently working on integrating PayPal into an Angular 5 project. The code snippet below shows how I render PayPal buttons using a function: ngAfterViewChecked(): void { if (!this.addScript) { this.addPaypalScript().then(() => { ...

Unexpected absence of Aria tags noticed

I've been working on integrating ngAria into my project. I have injected it into my module and created the following HTML: First Name: <input role="textbox" type="text" ng-model="firstName" aria-label="First Name" required><br> Employee: ...

Can you determine the size of an unknown array in TypeScript?

Currently diving into TypeScript and tackling some TDD challenges. Within my model file, I'm working with a property named 'innovatorQuotes' that should be an array containing strings with a fixed length of 3. I'm struggling to nail dow ...

Creating layers of object declarations

Looking for assistance on the code snippet below. type Item = { id: number; size: number; } type Example = { name: string; items: [ Item ]; } var obj: Example = { name: "test", items: [ { i ...

Angular JavaScript does not take effect on elements inserted into ui-view

When transferring the code from main.html to index.html, the javascript functions smoothly. The click function successfully triggers the ripple effect. Link: Ripple Click Effect Google Material Design However, upon extracting the code to main.html and in ...

What is the best way to recycle a single modal in Ionic?

Apologies for the vague title, but I'm facing an issue with creating a single modal to display data from multiple clickable elements, rather than having separate modals for each element. For example, when I click on item 1, its data should be shown in ...

Executing a Restangular GET request with information included

Is there a way to make a GET request with data in Restangular? My AngularJS app uses Parse as the backend, and for logging in, it needs a GET request with data: curl -X GET \ -H "X-Parse-Application-Id: ..." \ -H "X-Parse-REST-API-Key: ..." ...

Angular2 with Typescript is experiencing issues with the implementation of operations in JavaScript

I'm struggling to implement a D3 graph example in my Angular 2 TypeScript application. The issue arises with the lines marked with "----> Error". I have no clue on how to tackle this problem. Can anyone offer some assistance? d3.transition().dura ...

Is one-way data binding possible in Angular?

I'm inquiring about one-way data binding with AngularJS. Imagine we have two input boxes on the same page, labeled A and B. Is it possible for input A to change input B, without input B affecting input A? I am aware of Angular's bindonce featu ...