Search code examples
angularangular-ngselect

Angular5 ngselect with object doesn't select


I'm pretty new to Angular and I'm looking for a good way to solve this issue but posts I've read were not relevant.

I have a first dropdown that needs to store objects, then upon selecting there a second dropdown that needs to be populated. This is on a "user preference page", so selected values need to be saved. This works so far (the controller is saving selected values in a service and upon going back to that preference page, I put back selectedValues to whatever was in the service - I'm guessing this is the correct approach).

The issue is that when going out of that page and coming back in, the 1st dropdown doesn't select what was previously selected by the user (which stores an object, a "LsafIdp") while the 2nd dropdown does (which stores a simple string). How should I handle this in order for the 1st dropdown to show the selected object ?

NB: I'm running Angular 5

HTML file

    <div class="form-group">
        <label for="idp">IDP</label>
        <select class="form-control" id="idp" required [(ngModel)]="selectedIdp" name="idp" (change)="onIdpSelection()">
            <option *ngFor="let idp of idps" [ngValue]="idp">{{idp.idpName}}</option>
        </select>
    </div>

    <div class="form-group">
        <label for="study">Study</label>
        <select class="form-control" id="study" required [(ngModel)]="selectedStudy" name="study" (change)="onStudySelection()">
            <option *ngFor="let study of selectedIdp.studyList" [ngValue]="study">{{study}}</option>
        </select>
    </div>

    Selected:
    <p>IDP as json: {{selectedIdp | json}}</p> <!-- this works, shows correctly the object saved in the service -->

</form>

TS file:

@Component({
    selector: 'app-context',
    templateUrl: './context.component.html',
    styleUrls: ['./context.component.scss'],
    //encapsulation: ViewEncapsulation.Emulated
})
export class ContextComponent implements OnInit {
    selectedIdp: LsafIdp; // model for the first <select>
    selectedStudy: string; // model for the 2nd <select>
    idps: LsafIdp[];

    constructor(private lsafService: LsafService) {
        this.selectedIdp = new LsafIdp();
    }

    ngOnInit() {
        // on init load the values from the service
        if(this.lsafService.idpSelected!=null)
            this.selectedIdp = this.lsafService.idpSelected;
        if(this.lsafService.studySelected!=null)
            this.selectedStudy = this.lsafService.studySelected;

        this.lsafService.getLsafInfo().subscribe(
            response => {
                let lsafInfo: LsafInfo = response;
                this.idps = lsafInfo.idpList;
            }
        );
    }

    onIdpSelection() {
        console.log("IDP selected: " + this.selectedIdp.idpName);
        this.lsafService.idpSelected = this.selectedIdp;
    }

    onStudySelection() {
        console.log("Study selected: " + this.selectedStudy);
        this.lsafService.studySelected = this.selectedStudy;
    }


}

I tried many things, like: (had many hopes for this one)

<option *ngFor="let idp of idps" [ngValue]="idp" [selected]="idp.idpName === selectedIdp.idpName">{{idp.idpName}}</option>

but all my attemps failed

Thanks!


Solution

  • Ok after a lot of research I finally found

    The correct way was to use the [compareWith] on the <select> and define that method in the controller.

        <select class="form-control" id="idp" required [(ngModel)]="selectedIdp" name="idp" (change)="onIdpSelection()" [compareWith]="compareIdpByName" >
            <option *ngFor="let idp of idps" [ngValue]="idp">{{idp.idpName}}</option>
        </select>
    
    compareIdpByName(item1: LsafIdp, item2: LsafIdp){
        return item1.idpName === item2.idpName;
    }