摘要:但實際上這時程序并沒有計算手續(xù)費。經過排查并查閱文檔之后,發(fā)現(xiàn)是的問題。本文沒有具體介紹和管道,關于這部分可以參考文中給出的鏈接
事情起源于在項目中遇到的一個小問題:項目中需要一個輸入框輸入賣出產品數(shù)量,并且在用戶輸入后根據(jù)輸入數(shù)據(jù)計算手續(xù)費。很自然的我用了ng-model和ng-change,并且一般情況下沒什么問題。問題是:輸入框下還有一個按鈕是全部賣出,點擊這個按鈕程序會自動設置賣出額。但實際上這時程序并沒有計算手續(xù)費。
經過排查并查閱文檔之后,發(fā)現(xiàn)是ng-change的問題。Angular關于ng-change的官方文檔的提示是:
The expression is not evaluated when the value change is coming from the model.
ng-change的源碼也很簡單:
var ngChangeDirective = valueFn({ restrict: "A", require: "ngModel", link: function(scope, element, attr, ctrl) { ctrl.$viewChangeListeners.push(function() { scope.$eval(attr.ngChange); }); } });
從中我們也可以看出ng-change只做了view到model的監(jiān)聽。所以當我們直接在js中修改ng-model的變量時并不會觸發(fā)ng-change。
問題找到了,解決方案也不難,放棄ng-change,改用$watch就行了。
但是就這么結束了嗎?一個變量從view變化開始到同步更新到model到底經歷了什么呢?反過來呢,是一樣的嗎?
所以我又去看了看ng-model的源碼,并沒有什么收獲,不過意外的了解到了這么個點:
ng-change是在model值變化之前執(zhí)行的。ng-model源碼中有這么個函數(shù):
function setupModelWatcher(ctrl) { // model -> value // !!!Note: we cannot use a normal scope.$watch as we want to detect the following: // !!!1. scope value is "a" // !!! 2. user enters "b" // !!!3. ng-change kicks in and reverts scope value to "a" // -> scope value did not change since the last digest as // ng-change executes in apply phase // !!!4. view should be changed back to "a" ctrl.$$scope.$watch(function ngModelWatch(scope) { var modelValue = ctrl.$$ngModelGet(scope); // if scope model value and ngModel value are out of sync // This cannot be moved to the action function, because it would not catch the // case where the model is changed in the ngChange function or the model setter if (modelValue !== ctrl.$modelValue && // checks for NaN is needed to allow setting the model to NaN when there"s an asyncValidator // eslint-disable-next-line no-self-compare (ctrl.$modelValue === ctrl.$modelValue || modelValue === modelValue) ) { ctrl.$$setModelValue(modelValue); } return modelValue; }); }
里面的注釋解釋了為什么變量model值的修改要在ng-change之后,因為ng-change中很可能會把變量的值又修改回去,這樣變量值事實上就并沒改變(寫api真的是什么情況都要考慮到啊?。。?。關于這一點,以及前面的問題這里有一個demo代碼:http://runjs.cn/code/wnmdzvwg
既然看源碼沒什么收獲,那么就去網上搜搜文章看看吧。這個過程中找到一篇很好的文章,這篇文章介紹了
$formatters,$parsers,$render以及$setViewValue。這里就不再介紹了,如果需要學習,原文在這里:http://blog.csdn.net/qq_17371...
在學習$setViewValue時也發(fā)現(xiàn)一個很容易被坑的點:在調用$setViewValue時,如果參數(shù)是引用變量,那么如果引用變量地址沒變,則這個變量被認為沒有改變,如 var map = [‘er’, ’tr’];那么map.pop();之后$setViewValue并不認為map值改變了。關于這個具體可以看我對這個問題的回答。順便也附上demo代碼:http://runjs.cn/code/cm7d3pcf
ng-model也有這個問題,這個在ng-model源碼注釋中可以看到:
However, custom controls might also pass objects to this method. In
this case, we should make a copy of the object before passing it to
$setViewValue. This is because ngModel does not perform a deep
watch of objects, it only looks for a change of identity.If you only change the property of the object then ngModel will not
realize that the object has changed and will not invoke the $parsers
and $validators pipelines.
從上面也可以看到其實一個變量的更新由view到model和model到view不止$formatters和$parsers管道,那么還有哪些呢?
在查了一圈資料后找到一個很清晰的解釋:https://stackoverflow.com/que...,大家其實只需要看問題的回答,問題實在太長了。。。
這個回答中有個demo鏈接,我copy了一下并做了寫小修改放在這個地址了:http://runjs.cn/code/qte0mm49,這個demo很清晰的顯示了變量更新的過程,細節(jié)就不再累述了,這里只把結果總結如下:
從model到view:
model值修改 ----> $formatters管道 ----> $render函數(shù) ----> $validators ----> $watch函數(shù)
從view到model:
view值修改 ----> $setViewValue函數(shù)----> $parsers管道 ----> $validators ----> $viewChangeListener函數(shù) ----> $watch函數(shù)
我們也可以直接調用$setViewValue函數(shù)去直接改變$viewValue 的值,流程會和上面一樣。
注意在使用$setViewValue時一定要警惕參數(shù)是引用變量的情況,這個坑在上文也已經提到了。
本文沒有具體介紹$formatters 和 $parsers 管道,關于這部分可以參考文中給出的鏈接
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://www.ezyhdfw.cn/yun/107586.html
摘要:,的事件回調函數(shù)中調用的操作方法。以為例調用關系模式實際就是將中的改名為,調用過程基本一致,最大的改良是間的雙向綁定。和間,有一個對象,可以操作修改,使用。 參考:MVC,MVP 和 MVVM 的圖示 - 阮一峰http://www.ruanyifeng.com/blo...Web開發(fā)的MVVM模式http://www.cnblogs.com/dxy198...界面之下:還原真實的MV...
摘要:,的事件回調函數(shù)中調用的操作方法。以為例調用關系模式實際就是將中的改名為,調用過程基本一致,最大的改良是間的雙向綁定。和間,有一個對象,可以操作修改,使用。 參考:MVC,MVP 和 MVVM 的圖示 - 阮一峰http://www.ruanyifeng.com/blo...Web開發(fā)的MVVM模式http://www.cnblogs.com/dxy198...界面之下:還原真實的MV...
摘要:我們下面來看看的源碼這是其中一個,在不同的指令下的代碼都不太一樣,但是其作用基本一致,但是從這里我們就可以看出的到底在干什么事了。 這篇文章是我兩年前在博客園寫的,現(xiàn)在移植過來,不過Angular 1.x 在國內用的人已經不多了,希望能幫助到有需要的人 在我開始著手 ngModel 的領域時候,有一個問題很令我糾結,那就是 $render 到底是做什么的呢?查了很多資料都只是簡單的描述...
摘要:它通過數(shù)據(jù)模型進行鍵值綁定及事件處理,通過模型集合器提供一套豐富的用于枚舉功能,通過視圖來進行事件處理及與現(xiàn)有的通過接口進行交互。 本人兼職前端付費技術顧問,如需幫助請加本人微信hawx1993或QQ345823102,非誠勿擾 1.為初學前端而不知道怎么做項目的你指導 2.指導并扎實你的JavaScript基礎 3.幫你準備面試并提供相關指導性意見 4.為你的前端之路提供極具建設性的...
摘要:的思想非常先進,摒棄了那種復雜的構建模式,采用了組件化開方的方,那我們一起來看一看,一個基礎的組件是什么樣子的呢。 angular2的思想非常先進,摒棄了angular1那種復雜的構建模式,采用了組件化開方的方,那我們一起來看一看,一個基礎的組件是什么樣子的呢。angular2-demoshowImg(http://static.xiaomo.info/images/angular.p...
閱讀 1388·2023-04-26 02:38
閱讀 1010·2023-04-25 20:13
閱讀 3649·2021-11-19 11:31
閱讀 2451·2019-08-30 15:55
閱讀 2784·2019-08-30 14:11
閱讀 3221·2019-08-30 13:45
閱讀 1437·2019-08-29 18:41
閱讀 1226·2019-08-29 16:18