0

I have 2 select boxes, and setting either one should set the second one to 0.

HTML

<select [(ngModel)]="testVar" (ngModelChange)="testFunc($event)">
  <option value="0">no</option>
  <option value="1">yes</option>
  <option value="2">maybe</option>
</select>

<select [(ngModel)]="testVar2" (ngModelChange)="testFunc($event)">
  <option value="0">no</option>
  <option value="1">yes</option>
  <option value="2">maybe</option>
</select>

COMPONENT

  testVar = 0;
  testVar2 = 1;

  testFunc(){
    this.testVar2 = 0;
    console.log(this.testVar2);
  }

This works fine when first hitting the page and changing either box, but after setting the second select back to 1, the two way binding is lost. The console log seems to indicate the model is being updated, but the select box is not responding. What am I missing?

plunkr

Devin D
  • 98
  • 11
  • I've seen the stackoverflow and github discussion about the doubling up of having [(ngModel)] and (ngModelChange), but couldn't get any other combination working any better. – Devin D Nov 09 '17 at 16:14

3 Answers3

1

Found a solution here. The trick was to call ChangeDetectorRef.detectChanges() in the function prior to resetting the value.

Note however that it is required to use both [(ngModel)] and (ngModelChange)... just don't ask me why XD

Working plunkr

Devin D
  • 98
  • 11
0

I managed to get the desired behaviour by changing your second select box from

<select [(ngModel)]="testVar2" (ngModelChange)="testFunc($event)">
 <option value="0">no</option>
 <option value="1">yes</option>
 <option value="2">maybe</option>
</select>

To

<select [(ngModel)]="testVar2">
 <option value="0">no</option>
 <option value="1">yes</option>
 <option value="2">maybe</option>
</select>

I'm not 100% as to why it didn't at least force the second value to always be 0, but I can tell you that your initial binding is wrong. The [(ngModel)] (Banana in a box syntax) is built up of two things.

  • [ngModel] Means that you are binding a value from your component to the html. So, for example, if you programmatically update a variable, it will be reflected in your HTML/Child component.

  • (ngModel) Means that the value you pass ngModel will be bind to any changes that the HTML/component makes to it.

Using both of these together, we create the two-way binding. Your component will update any child component/html that uses a value, and the html/component will update your component whenever it changes the value. However, when you also specify (ngModelChange)="testFunc($event)" you are overwriting the callback binding with your own. Removing this will fix your code.

Hope this helps, and if anyone knows why testFunc wasn't always making the value of testVar2 0, please comment as I would like to know.

Lewis Campbell
  • 343
  • 2
  • 11
  • Thanks @Lewis, huh could have sworn I tried that. Unfortunately my demo is dumbed down, I need the second box to call testFunction. While I can use the function for all variable setting, using just [ngModel] with (ngModelChange) has the behavior I describe in my question. – Devin D Nov 09 '17 at 16:52
  • Also curious is that I am using [(ngModel)] and (ngModelChange) together in many other fields to achieve the two-way bind and fire off a debounced autosave, and it's working great. Shouldn't these not work as well? What are you proposing happens to the (ngModelChange) when doubling up? I've had no issues with them not firing or with dirty reads. – Devin D Nov 09 '17 at 17:00
0

Small change in your app component. Pass value while calling testFunc and set values inside the function.

//our root app component
import {Component, NgModule, VERSION} from '@angular/core'
import {BrowserModule} from '@angular/platform-browser'
import { FormsModule } from '@angular/forms';
@Component({
  selector: 'my-app',
  template: `
    <select [(ngModel)]="testVar" (ngModelChange)="testFunc($event, 0)"> //Change
      <option [ngValue]="0">no</option>
      <option [ngValue]="1">yes</option>
      <option [ngValue]="2">maybe</option>
    </select>

    <select [(ngModel)]="testVar2" (ngModelChange)="testFunc(0, $event)"> //Change
      <option [ngValue]="0">no</option>
      <option [ngValue]="1">yes</option>
      <option [ngValue]="2">maybe</option>
    </select>
  `,
})
export class App {
  name:string;
  testVar: number = 0;
  testVar2: number = 1;
  constructor() {}
  testFunc(val: number, val1: number){  //Change
     this.testVar = val;
     this.testVar2 = val1;
  }
 }
}

@NgModule({
imports: [ BrowserModule, FormsModule ],
  declarations: [ App ],
  bootstrap: [ App ]
})
export class AppModule {}
Meet Shah
  • 59
  • 3
  • Thanks, this does indeed work to set the opposite box to 0, but when I update the second box to something besides 0 it should reset itself to 0, not the first box. With this logic passing params to the function still misbehaves. – Devin D Nov 09 '17 at 17:11
  • In your question, you said that setting either one of them should reset the other one to 0. So, setting 2nd one should reset the first one. Right? Do you want to reset both boxes? If you want the second one always 0, then just pass one parameter $event and set testVar2 to 0 or put conditions accordingly But, this logic will work. – Meet Shah Nov 09 '17 at 17:57
  • Sorry for the confusion, I do need setting either box to always set the second box to 0. What I was saying in my question is that this works great exactly once each load, regardless of which box you change. Is this [new plunkr](https://plnkr.co/edit/tpl:AvJOMERrnz94ekVua0u5?p=preview) what you mean? It still exhibits this "only once" behavior... – Devin D Nov 09 '17 at 18:18
  • Sorry wrong plunkr link [Try this one](https://plnkr.co/edit/woDJi6w8t0Eutn07ULCI?p=preview) – Devin D Nov 09 '17 at 18:25