3

I have 2 dropdowns and I populate 2nd dropdown based on the value of dropdown 1. I have scenario to Edit and populate the dropdown values based on the grid.

enter image description here

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

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

Html is below

<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)="getContacts($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>

When I click on Edit link onEdit method is called and selects/assigns the values but fails on selction of contacts.

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.populateContacts(relationship);
}

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

It fails on the line when i am trying to find contact in contacts array.

enter image description here

I assume the reason is service.getcontacts is http call and it takes time and when i am trying to find the contact object in this.contacts array which is undefined.

Is there a way to wait for getContacts in populateContacts method?

Edit 1:

my new code looks like this

private populateContacts(relationship: Relationship) {
        //TODO: find a way to use 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 getContacts(businessAreaObj) {
    this.businessAreaService.getContacts(businessAreaObj.id)
        .subscribe(
        contacts => this.contacts = contacts,
        error => this.errorMessage = error);
}

Edit 2:

@Gunter' solution works for Edit case but if i manually select dropdown value on BA it does not load contacts in contacts dropdown.

enter image description here

Kamran Pervaiz
  • 1,861
  • 4
  • 22
  • 42

1 Answers1

1

You need to return the Observable. For this you must not call subscribe()

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

    }
}

then you can call it, get an Observable you can subscribe to, and in the callback you call the follow-up code:

private populateContacts(relationship: Relationship) {
    this.getContacts(relationship.businessAreaId)
    .subscribe(val => this.selectedContact = this.contacts.find(contact => contact.id === relationship.contacts[0].id));
}
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • thanks for your response Gunter, this.businessAreaService.getContacts is already observable. its an http call. i have 2 scenario here. 1. populate contacts dropdown based on BA value 2. select value when Edit is clicked. I do not require observable for 1st scenario. its like i am calling same method for both cases. but let me try your solution first :) – Kamran Pervaiz Aug 25 '16 at 09:54
  • as expected above solution works perfectly well for Edit case but when i am creating new record and select value from BA it does not populate contacts dropdown because i am not subscribing on change...I think getContacts should subscribe and in populate contacts i will call the service directly?I was trying to avoid another http call and use the same array this.contacts. is there a way? – Kamran Pervaiz Aug 25 '16 at 09:59
  • That's a bit complex to follow all these details. Sounds like http://stackoverflow.com/questions/36271899/what-is-the-correct-way-to-share-the-result-of-an-angular-2-http-network-call-in – Günter Zöchbauer Aug 25 '16 at 10:03
  • sorry for weird explanation. when i call getcontacts() I assign my array to this.contacts. I just want to use the same array in populateContacts() method. – Kamran Pervaiz Aug 25 '16 at 10:13
  • the `contacts` from `getContacts` are forwarded to the subscriber. `val` in `populateContacts()` will be the same array (the one returned from `.map(contacts => this.contacts = contacts)` (the result of `this.contacts = contacts` will be `contacts`) – Günter Zöchbauer Aug 25 '16 at 10:16
  • thanks it works fine for when i click on Edit, perfectly fine. but when i select dropdown value of BA to some other value its not loading new contacts thats is the problem. please see the updated code which fixes both problem but is a lttle ugly code :( – Kamran Pervaiz Aug 25 '16 at 10:32
  • You now need to call `subscribe()` (`getContacts(...)subscribe()`) everywhere. It's probably the best if you create another method that you can call from elsewhere that does the subscribe `getContacts2() {this.getContacts().subscribe();}`. `getContacts2` isn't actually good naming but I leave it to you as exercise ;-) – Günter Zöchbauer Aug 25 '16 at 10:40
  • I am sorry I didn't get your point. Is it possible to Edit/update your answer and append it? – Kamran Pervaiz Aug 25 '16 at 10:49
  • When you don't call `subscribe()` on an observable, it is not doing anything. They are lazy. Because we changed `subscribe()` to `map()` in `getContacts()` it doesn't do anything anymore when called (except from `populateContacts()` because there `subscribe()` is called. You need to add a helper method that does the `subscribe()` call. That's all. – Günter Zöchbauer Aug 25 '16 at 10:54