Search code examples
angulartypescriptangular2-databinding

Angular 11, how to bind a new object in template, to component


When a user loads a different selection (object) from the option drop-down list, I would like to get the NEW object returned in the (change) function. But, it is returning the default object every time, even though the select changes correctly. This type of binding was working in AngularJs when using $scope. Not sure if my Angular 11 ngModel, etc. is correct. (I have imported FormsModule)

component.ts...

 public selectedQuery: any;


// default object...
 public myQueries: [{ 
 myQueryId: number, 
 myQueryCreatedDate: Date, 
 myQueryString: string 
 }] = [{
    myQueryId: 0,
    myQueryCreatedDate: new Date(),
    myQueryString: "Please select a query"
  }]


dropDownListBuild(); // function builds correctly, loads myQueries array with options
...

this.selectedQuery = this.myQueries[0]; // gets set as default
...


onQueryChange(query: any) {
    console.log(this.selectedQuery + query); // not seeing any change happen
  }

component.html...

<div class="selectClass">
    <select [(ngModel)]="selectedQuery" (change)="onQueryChange(selectedQuery)">
            <option *ngFor="let opt of myQueries" [ngValue]="selectedQuery"> {{opt.myQueryString}}</option>
     </select>       
</div>

Solution

  • Change your HTML code to the following:

    <div class="selectClass">
      <select [(ngModel)]="selectedQuery" (ngModelChange)="onQueryChange($event)">
        <option *ngFor="let opt of myQueries" [ngValue]="opt">
          {{ opt.myQueryString }}
        </option>
      </select>
    </div>
    

    Changes:

    1. Use (ngModelChange)="onQueryChange($event)" instead of (change)=onQueryChange(selectedQuery) to get new query - more details below.
    2. Change [ngValue]="selectedQuery" to [ngValue]="opt" - previous version meant that you were repeating three times the same query as value, you just changed displayed text (so each option was presented with correct displayed text but values were always the same).

    More details on change event: (change) is bound to change event fired even without Angular, it's just classic input change event. You can use it without ngModel but using with ngModel doesn't work particularly well as this event is (or at least may be) fired before ngModel is updated.

    That's why you should use dedicated (ngModelChange) which is an output of ngModel directive so it is fired always after model from ngModel is changed.

    Btw. If you don't need to detect the moment when query is changed but instead you just need to have correct query stored in selectedQuery attribute - just apply second fix and you can remove ngModelChange.