Angular ngModelChange中的大坑

本人后端程序员, 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);
}

感谢阅读!  

  • 7
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Angular使用iframe有几种方法。一种是通过在模板直接使用iframe标签,设置src属性来加载网页。例如,你可以在模板使用以下代码来创建一个iframe元素: <iframe [src]="iframeUrl" class="Iframe" width="300px" height="500px" style="padding: 0" scrolling="no" frameborder="0"> <p>当前浏览器不支持iframe</p> </iframe> 在这个例子,iframeUrl是一个在组件定义的变量,用来指定要加载的网页的URL。 另一种方法是使用ViewChild指令来获取到iframe元素的引用,然后通过修改它的src属性来加载网页。例如,你可以在组件的HTML模板添加以下代码: <iframe #frame class="frame" [src]="srcUrl" width="100%" frameborder="0"> </iframe> 然后,在组件的代码,你可以使用ViewChild指令来获取到iframe元素的引用,并在需要的时候修改它的src属性。例如,你可以在组件类添加以下代码: @ViewChild('frame') frame: ElementRef; 然后,在需要修改iframe的地方,你可以使用以下代码来修改src属性: this.frame.nativeElement.src = newUrl; 这样就可以通过iframe在Angular加载网页了。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [angular-through-iframe:如何通过 iframe 使用 angular.js](https://download.csdn.net/download/weixin_42127783/19261318)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [angulariframe的使用](https://blog.csdn.net/Fat_Shady_/article/details/119326333)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [angular跨域设置iframe自适应高度,去滚动条。](https://blog.csdn.net/ITronger/article/details/127907056)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值