Waiting for a synchronous method in Angular 2

I am faced with a scenario where I need to populate the values of the second dropdown based on the selection made in the first dropdown. This requirement arises during editing, especially when populating dropdown values based on grid data.

https://i.sstatic.net/KlruP.png

private loadContacts(relationship: Relationship) {
        this.fetchContacts(relationship.businessAreaId);
        this.selectedContact = this.contacts.find(contact => contact.id === relationship.contacts[0].id);
    }

    private fetchContacts(businessAreaObjectOrId) {
        if (businessAreaObjectOrId === NaN)
            businessAreaObjectOrId = businessAreaObjectOrId.id;
        this.businessAreaService.getContacts(businessAreaObjectOrId)
            .subscribe(
            contacts => this.contacts = contacts,
            error => this.errorMessage = error);
    }

The following is how the HTML looks like:

<tr *ngFor="let relationship of relationships">
                <td>{{relationship.supplierName}}</td>
                <td>{{relationship.businessArea}}</td>
                <td>{{relationship.contacts[0].name}}</td>
                <td><a href="javascript:void(0)" (click)="onEdit(relationship)">Edit</a></td>
            </tr>
            <tr class="active">
                <td>
                    <select class="form-control" name="supplier" required
                            [(ngModel)]="selectedSupplier" #supplier="ngModel">
                        <option *ngFor="let supplier of suppliers" [ngValue]="supplier">{{supplier.name}}</option>
                    </select>
                    <div [hidden]="supplier.valid || supplier.pristine" class="alert alert-danger">
                        Supplier is required
                    </div>
                </td>
                <td>
                    <select class="form-control" name="businessArea" required
                            [(ngModel)]="selectedBusinessArea" #businessArea="ngModel" (ngModelChange)="fetchContacts($event)">
                        <option *ngFor="let businessArea of businessAreas" [ngValue]="businessArea">{{businessArea.name}}</option>
                    </select>
                    <div [hidden]="businessArea.valid || businessArea.pristine" class="alert alert-danger">
                        Business Area is required
                    </div>
                </td>
                <td>
                    <select class="form-control" name="contact" required
                            [(ngModel)]="selectedContact" #contact="ngModel">
                        <option *ngFor="let contact of contacts" [ngValue]="contact">{{contact.name}}</option>
                    </select>
                    <div [hidden]="contact.valid || contact.pristine" class="alert alert-danger">
                        Contact is required
                    </div>
                </td>
                <td>
                    <input type="button" value="Add" class="btn btn-default" (click)="onSubmit()" [disabled]="!factoryRelationshipForm.form.valid" />
                </td>
            </tr>

The issue occurs when selecting an item from the contacts dropdown after clicking the Edit link.

private onEdit(relationship: Relationship): void {
    relationship.inEditMode = true;
    this.selectedSupplier = this.suppliers.find(supplier => supplier.id === relationship.supplierId);
    this.selectedBusinessArea = this.businessAreas
        .find(businessArea => businessArea.id === relationship.businessAreaId);
    this.loadContacts(relationship);
}

private loadContacts(relationship: Relationship) {
    this.fetchContacts(relationship.businessAreaId);
    this.selectedContact = this.contacts.find(contact => contact.id === relationship.contacts[0].id);
}

The issue arises at a particular point while trying to find a contact within the contacts array.

https://i.sstatic.net/MamMs.png

This problem might be due to the asynchronous nature of the service.getcontacts HTTP call, which causes delays in loading the contacts data into the contacts array resulting in "undefined".

Is there any way to implement a delay or wait for the getContacts method within the populateContacts function?

Edit 1:

My revised code implementation:

private loadContacts(relationship: Relationship) {
        //TODO: Implement a mechanism to utilize this.contacts/getContacts
        this.businessAreaService.getContacts(relationship.businessAreaId)
            .subscribe(val => {
                console.log(val);
                this.contacts = val;
                this.selectedContact = this.contacts.find(contact => contact.id === relationship.contacts[0].id)
            });
    }

private fetchContacts(businessAreaObj) {
    this.businessAreaService.getContacts(businessAreaObj.id)
        .subscribe(
        contacts => this.contacts = contacts,
        error => this.errorMessage = error);
}

Edit 2:

@Gunter's solution works well for the Edit case, but manual selection of a value in the BA dropdown does not trigger loading the contacts in the contacts dropdown.

https://i.sstatic.net/8QTmC.png

Answer №1

To obtain the desired result, it is important to remember that you should return the Observable and avoid directly calling subscribe().

private retrieveContacts(businessAreaObjorId) {
    if (businessAreaObjorId === NaN)
        businessAreaObjorId = businessAreaObjorId.id;
    return this.businessAreaService.getContacts(businessAreaObjorId)
        .catch(error => this.errorMessage = error)
        .map(
        contacts => this.contacts = contacts);

    }
}

Once you have obtained the Observable, you can then subscribe to it. In the callback function, you can proceed with the necessary follow-up code:

private fillInContacts(relationship: Relationship) {
    this.retrieveContacts(relationship.businessAreaId)
    .subscribe(val => this.selectedContact = this.contacts.find(contact => contact.id === relationship.contacts[0].id));
}

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

What is the best way to receive a notification once the final observable has completed emitting its values?

In the past, we only made one call to the API reqFinanceDataWithFilters(req): Observable<any> { return this.http.post(env.baseUrl + req.url, req.filters) .pipe(map(this.extractResults)); } However, the response from this single request was a ...

Angular application displays Msal v2 interaction_in_progress during login process

Encountering a unique issue with MSAL authentication in our app - we're seeing the msal interaction_in_progress error only during the initial login, which disappears upon refresh but reappears whenever a user logs out and back in. Check out these sni ...

The module has defined the component locally, however, it has not been made available for

I have developed a collaborative module where I declared and exported the necessary component for use in other modules. import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { DateslideCompone ...

Updating icon of a row in a table based on its position with *ngFor

I am currently working with a table that contains a list of songs. My goal is to toggle the source of an icon in a specific row based on its index (for actions like play/pause, like/unlike). However, at the moment, the icon only changes in the first row re ...

Retain input data when navigating and returning in the browser using Angular

When implementing a search feature in my program, I use an interactive form to collect user input. Upon submission, the form data is converted into JSON format along with the search filters and redirected to another page where a REST service is utilized to ...

What is the best way to specify data types for all attributes within an interface?

In building an interface for delivering strings in an i18n application: interface ILocaleStringsProvider { 'foo': string 'bar': string 'baz': string 'blablabla': string // numerous other string properties ...

What is the best way to display a "floating" message?

Upon successful change of a password and closure of this modal form... https://i.sstatic.net/weduD.png ...I aim to display a brief notification in the bottom-right corner of the page or browser with the message "Password changed" for 1 or 2 seconds (auto ...

retrieve the state property from NavLink

I am encountering an issue with passing objects through components in my project. Specifically, I have a chat object within a component that defines a NavLink. When a user clicks on the ChatsElement, which is a link, the page navigates to the URL /friends/ ...

Adjust validation message and minimum value when radio button is altered in Angular application

Seeking a way to dynamically set a validation message and minimum value based on a radio button selection. Currently, there are two radio buttons for either 9 or 18 holes, each with a corresponding input (used in a golf handicap calculator app). The goal i ...

There was an issue encountered while attempting to differentiate an object in the Angular datatable results. The data table only accepts arrays and iterables

Looking to retrieve user data from an API using the httpClient post method in Angular 5, I faced a challenge as I couldn't properly display the retrieved information in a datatable. Below are snippets of the code that I have experimented with: User ...

Tips for Successfully Transmitting Information via Mat-Dialog

Having trouble passing data from a dialog back to the parent component. Specifically, I'm struggling with updating the value of an array in the `afterClosed` function. I've tried using `patchValue` and `setValue`, but it doesn't seem to be w ...

Trying out getModifierState in Karma/Jasmine

What is the recommended approach for testing this Angular method? public detectCapslock(event: KeyboardEvent): void { let capsOn: boolean = event.getModifierState && event.getModifierState("CapsLock"); if (capsOn) { ...

At times, JavaScript interacts with Selenium to click on the login button before I have the chance

I have a challenge while attempting to log in to Twitter using Selenium webdriver, here is the code I am working with: const {Builder, By} = require("selenium-webdriver"); (async function example() { let driver = await new Builder().forBrowser(' ...

The data source retrieved through the "get" API method is missing from the mat-table

Recently, I've started working with angularCLI and I'm facing an issue in creating a table where the dataSource is fetched from a fake API. Let me share my component class: import { Component, OnInit } from '@angular/core'; import { Fo ...

Tips for successfully sending dual Subjects/Actions flows as HTTP Parameters in a GET call to retrieve a solo object or an array of objects in Angular with the help of RxJS

GOAL: My objective is to retrieve a single object and/or a range of objects from the backend service by utilizing RxJS and passing user inputs as HTTP parameters. For instance, I am leveraging declarative RxJS and have two Subjects (Action streams) to capt ...

Can you customize the "rem" values for individual Web Components when using Angular 2's ViewEncapsulation.Native feature?

I'm interested in creating a component with ViewEncapsulation.Native that utilizes Bootstrap 4 while others are using Bootstrap 3. Below is the component code with Bootstrap 4: import { Component, ViewEncapsulation } from '@angular/core'; i ...

generate a new canvas within an Angular 6 framework at a library

I am in the process of developing a unique Angular library that will enable image cropping using canvas. I initialized the library with "ng generate library" command, but when attempting to draw on the canvas, no results are visible. Here is the code from ...

Utilizing Angular 2 or TypeScript to Retrieve Visitor's Location

I initially began using ServerVariables["HTTP_CF_IPCOUNTRY"] on the backend server, but it's proving to be too slow. I'm looking for an Angular or TypeScript alternative to speed things up. ...

Using StencilJS to Incorporate CSS/SASS Styles from node_modules

I'm currently facing a challenge in importing a CSS file containing variables from a node_modules package. Despite trying to replicate the process outlined in stencil.config.ts, the builds continue to end up in a different location than intended, leav ...

Unit Testing Angular: Mastering Unit Testing for the .map() Function

I am in need of testing a service method, but I am unsure about how to achieve complete coverage for the code that gets executed as a result of calling another injected service method. The Service Method to be tested: @Injectable() export class BomRevisi ...