5

I have a select list that is bound to an Person property on my component using [ngValue]. When I change the select, the underyling selectedPerson property is updated as expected. However, the select does no default to the selected person on initialisation nor does it update if I change the selected person in code.

Any help into what I am missing would be greatly appreciated. Here's my code...

import {Component, OnInit, NgModule} from '@angular/core'
import {BrowserModule} from '@angular/platform-browser'
import { FormsModule } from '@angular/forms';

@Component({
  selector: 'my-app',
  template: `
      <form>
          <select [(ngModel)]="selectedPerson" 
                  name="selectedPerson">
              <option [ngValue]="null">Please choose...</option>
              <option *ngFor="let p of people"
                      [ngValue]="p"
                      [attr.selected]="p.personId === selectedPerson?.personId ? true : null ">{{p.name}}</option>
          </select>
          <p>The selected person is {{selectedPerson?.name}}</p>
          <button type="button" (click)="selectJane()">Select Jane</button>
          <button type="button" (click)="clearSelection()">Clear Selection</button>
      </form>`,
})
export class App implements OnInit {

  public ngOnInit() {

    this.people = [
      { personId: 1, name: "Tom" },
      { personId: 2, name: "Mary" },
      { personId: 3, name: "Jane" }
    ]
    this.selectedPerson = { personId: 2, name: "Mary" }
  }

  public people: Person[];
  public selectedPerson: Person;  

  public selectJane(){
    this.selectedPerson = { personId: 3, name: "Jane" }
  }

  public clearSelection(){
    this.selectedPerson = null;
  }  
}

export class Person {
  public personId: number;
  public name: string;
}

@NgModule({
  imports: [ BrowserModule, FormsModule ],
  declarations: [ App ],
  bootstrap: [ App ]
})
export class AppModule {}

...and here's a Plunker http://plnkr.co/edit/ag94mZO9Zggg1kZx8jJV

1

1 Answer 1

7

The problem is, that by using ngValue, the select expects the same reference, not just a similar looking object.

You could add a method to select by name like this:

public selectByName(name: string) {
   this.selectedPerson = this.people.find(person => person.name === name);
}

And then call it in your ngOnInit():

this.selectByName("Mary");
// or this.selectedPerson = this.people[2];

And in selectJane():

public selectJane(){
    this.selectByName("Jane");
}

Your updated Plunker

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

5 Comments

Thanks. That explains the problem clearly and gives me a solution. Having to update the selectedPerson object reference to be the same as the one in the list does feel like a bit of a pain though as in reality, these values would be coming from seperate http calls. I would therefore need to include an extra step to align the references for every select list in my app. I could bind to the id instead which would work but that would mean the is and name would get out of sync; that could be very confusing for a developer trying to debug some other issue.
Thinking about this more, shouldn't the [attr.selected]="p.personId === selectedPerson?.personId ? true : null" expression deal with keeping the correct <option> selected?
The selected attribute doesn't work with ngModel.
no! no! no!, ng2 team should change this pattern, should not be selecting by object only as html itself cannot work with object.
I have searched and Googled for hours, having the same problem. References... Why did I not think of that... Thanks!

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.