Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does ngmodelChange event not fire when component loads on a dropdown?

In my Angular 8 component, I have added bi-directional binding to a dropdown control.

The view

<select  (ngModelChange)='termSelectChanged($event)' [ngModel]="selected">
  <option [ngValue]="t" *ngFor='let t of termsColl'>{{t?.code}}</option>
</select>

The component code

export class AppComponent implements OnInit{


     public termsColl : Array<DDModel>;
     public selected : DDModel;
     
      constructor( private s : DDService ){}
      
    termSelectChanged( event  ){    
            alert('HIT');
    }
    
    
      ngOnInit(){
        
        //service call #1
        this.s.getDataForComplexBind().subscribe(  data => {
          this.termsColl = data;
         
        }, error => error );    


        //service call #2
        this.s.getOtherData(  ).subscribe( data => {
          
          //model changes here
          this.selected = this.termsColl[1];
          
        }, error => {  console.error(error);  });

                    
    }

} 

When the component loads, it executes ngOnInit() and sets the model-bound property Selected with the first element of the array termsColl. termsColl has data but the line this.selected = this.termsColl[1]; does not change the selected option to the first element in the dropdown. In fact, when the component loads, I was expecting it to fire the event ngModelChange but it did NOT fire the event either. I have added an alert() in the code but it did not show when the component loads. It shows only if I select an option from the dropdown. How do I change the code so it will execute the ngModelChange event when the component loads?

Here is my stackblitz https://stackblitz.com/edit/angular-version-yeg27j?file=src%2Fapp%2Fapp.component.ts

like image 332
eutychos tfar Avatar asked Dec 23 '22 16:12

eutychos tfar


2 Answers

I changed the ngModeChange input to DDModel and called your termSelectChanged() from inside the subscribe. I also changed [ngModel] to [(ngModel)]

<select  (ngModelChange)='termSelectChanged($event)' [(ngModel)]="selected">
  <option [ngValue]="t" *ngFor='let t of termsColl'>{{t?.code}}</option>
</select>
  termSelectChanged(selection: DDModel) {
    console.log("HIT", selection);
  }

  ngOnInit() {
    this.s.getOtherData().subscribe(
      data => {
        this.termsColl = data;
        this.selected = this.termsColl[0];
        this.termSelectChanged(this.selected);
      },
      error => {
        console.error(error);
      }
    );
  }

I can't tell you why changing this.selected from code does not trigger the ngModelChange. Maybe it's because ngModelChange is called in the template.

like image 100
unsignedmind Avatar answered Dec 25 '22 04:12

unsignedmind


You can use viewToModelUpdate() of ngModel to update the value and if you want to trigger the ngModelChange. You can find more about it here.

But you need to do the following changes.

In html template:

<select  (ngModelChange)='termSelectChanged($event)' [ngModel]="selected" #ngModel="ngModel">
  <option [value]="t" *ngFor='let t of termsColl'>{{t?.code}}</option>
</select>

You can see I am adding a reference to the ngModel in template, which I will use it in the component class.

In the component class:

export class AppComponent {
  name = "Angular 6";
  version = VERSION.full;

  public termsColl: Array<DDModel>;
  public selected: string;

  @ViewChild("ngModel") ngModel: NgModel;

  constructor(private s: DDService) {}

  termSelectChanged(event) {
    this.selected = event;
  }

  ngOnInit() {
    this.s.getOtherData().subscribe(
      data => {
        this.termsColl = data;
        this.ngModel.viewToModelUpdate(this.termsColl[1]);
      },
      error => {
        console.error(error);
      }
    );
  }
}

You can see I am using the ngModel reference to call the viewToModelUpdate with the value, which in return triggers the ngModelChange.

Since you are not using two way binding directly, you have to set the value to the selected variable inside the trigger function termSelectChanged.

Hope this would help you to achieve your requirement.

like image 42
Rishanthakumar Avatar answered Dec 25 '22 04:12

Rishanthakumar