本人后端程序员, Angular小菜鸡一枚, 文章内容可能有误, 还请务必指出.
先说结论
Angular中ngModelChange与ngModel属性, 在标签中出现的位置顺序决定ngModelChanges事件触发与Model的改变顺序.
如果ngModelChange出现在ngModel前面, 那么ngModelChange被触发的时候, model中变量的值还是没有change过的变量, 也就是视图层View之前的值.
如果ngModelChange出现在ngModel后面, 那么ngModelChange被触发的时候, model中变量的值就是当前视图层View中的值.
根据上面这个结论, 可以应该可以说在绝大多数场景下, ngModelChange都应该在ngModel的后面, 要是一不小心写反了, 程序就会有意想不到的结果.
我的经历
我尝试着通过angular编写一个计算器程序, 界面如下:
没有任何按钮, 只通过监听上面的输入和选择的更改, 执行计算操作.
代码如下:
<div nz-row [nzGutter]="[32,16]">
<div nz-col id="col1">
<div nz-col>
<input nz-input (ngModelChange)="calculate()" [(ngModel)]="this.num1" id="num1 " name="num1 " placeholder="操作数1 ">
</div>
<div nz-col>
<nz-select (ngModelChange)="this.calculate()" [(ngModel)]="this.cur_operator" [nzOptions]="this.operators ">
</nz-select>
</div>
</div>
<div nz-col id="col2 ">
<div nz-col>
<input nz-input (ngModelChange)="calculate()" [(ngModel)]="this.num2" id="num2 " name="num2 " placeholder="操作数2 ">
</div>
<div nz-col>
<input nz-input [(ngModel)]="this.num3" id="num3 " name="num3 " placeholder="答案 ">
</div>
</div>
</div>
按理来说, 只要监测到Model Change, 然后去执行计算操作, 就可以满足我的需求了.
然而, 我大意了. 这样的做法的结果就是:
虽然输入操作触发了ModelChange事件, 然而在ModelChange被触发的时候, 绑定的值并没有改变. 正如上图所示, 只有在左侧文本框已经变成12了, 这时结果文本框居然计算的是1+2的值(应该计算12+2).
这就很令人头痛了...
后来在百度和Google上搜了, 找到了问题所在: ngModelChange一定要跟在ngModel后面(也就是开篇我所描述的). 于是, 我将ngModelChange放到了ngModel后面, 问题迎刃而解.
我顺便尝试了下, 如果ngModel前后都有一个ngModelChange, 那么是否会在model改变前和改变后调用触发两次change事件呢?
答案是: 确实如我所想.
<div nz-col>
<nz-select (ngModelChange)="this.before()" [(ngModel)]="this.cur_operator"
(ngModelChange)="this.calculate()" [nzOptions]="this.operators ">
</nz-select>
如上代码, 在ngModel前后设定了change事件, 分别调用before和calculate方法, 它们都会在控制台中输出操作符绑定的变量operator_cur, 下面是option从+变成/时, 控制台的输出结果.
可见, 确实我的选择操作触发了两次change事件. 而且也确实是一先一后.
input事件
上面说了关于ModelChange事件的执行先后的问题, 下面介绍一个input事件, 绑定这个事件可以无视ngModel所在的位置. 只要用户发生了输入操作, 就会调用该方法, 并且一定是在model发生了改变后调用. 对于input这种文本框, 可以考虑使用这个事件, 因为这样就不需要上述不小心写反的问题.
美中不足是, 根据我目前的测试, 该事件仅能在一些需要键盘输入的控件上上被触发. 像刚刚那个selector是不能触发input事件的.
这是我得知这个事件的地方:
https://stackoverflow.com/questions/35359358/angular-2-change-event-on-every-keypress
I just used the event input and it worked fine as follows:
# in .html file :
<input type="text" class="form-control" (input)="onSearchChange($event.target.value)">
# in .ts file :
onSearchChange(searchValue: string): void {
console.log(searchValue);
}
感谢阅读!