摘要:但實(shí)際上這時(shí)程序并沒有計(jì)算手續(xù)費(fèi)。經(jīng)過排查并查閱文檔之后,發(fā)現(xiàn)是的問題。本文沒有具體介紹和管道,關(guān)于這部分可以參考文中給出的鏈接
事情起源于在項(xiàng)目中遇到的一個(gè)小問題:項(xiàng)目中需要一個(gè)輸入框輸入賣出產(chǎn)品數(shù)量,并且在用戶輸入后根據(jù)輸入數(shù)據(jù)計(jì)算手續(xù)費(fèi)。很自然的我用了ng-model和ng-change,并且一般情況下沒什么問題。問題是:輸入框下還有一個(gè)按鈕是全部賣出,點(diǎn)擊這個(gè)按鈕程序會(huì)自動(dòng)設(shè)置賣出額。但實(shí)際上這時(shí)程序并沒有計(jì)算手續(xù)費(fèi)。
經(jīng)過排查并查閱文檔之后,發(fā)現(xiàn)是ng-change的問題。Angular關(guān)于ng-change的官方文檔的提示是:
The expression is not evaluated when the value change is coming from the model.
ng-change的源碼也很簡(jiǎn)單:
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)聽。所以當(dāng)我們直接在js中修改ng-model的變量時(shí)并不會(huì)觸發(fā)ng-change。
問題找到了,解決方案也不難,放棄ng-change,改用$watch就行了。
但是就這么結(jié)束了嗎?一個(gè)變量從view變化開始到同步更新到model到底經(jīng)歷了什么呢?反過來呢,是一樣的嗎?
所以我又去看了看ng-model的源碼,并沒有什么收獲,不過意外的了解到了這么個(gè)點(diǎn):
ng-change是在model值變化之前執(zhí)行的。ng-model源碼中有這么個(gè)函數(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之后,因?yàn)閚g-change中很可能會(huì)把變量的值又修改回去,這樣變量值事實(shí)上就并沒改變(寫api真的是什么情況都要考慮到?。。。jP(guān)于這一點(diǎn),以及前面的問題這里有一個(gè)demo代碼:http://runjs.cn/code/wnmdzvwg
既然看源碼沒什么收獲,那么就去網(wǎng)上搜搜文章看看吧。這個(gè)過程中找到一篇很好的文章,這篇文章介紹了
$formatters,$parsers,$render以及$setViewValue。這里就不再介紹了,如果需要學(xué)習(xí),原文在這里:http://blog.csdn.net/qq_17371...
在學(xué)習(xí)$setViewValue時(shí)也發(fā)現(xiàn)一個(gè)很容易被坑的點(diǎn):在調(diào)用$setViewValue時(shí),如果參數(shù)是引用變量,那么如果引用變量地址沒變,則這個(gè)變量被認(rèn)為沒有改變,如 var map = [‘er’, ’tr’];那么map.pop();之后$setViewValue并不認(rèn)為map值改變了。關(guān)于這個(gè)具體可以看我對(duì)這個(gè)問題的回答。順便也附上demo代碼:http://runjs.cn/code/cm7d3pcf
ng-model也有這個(gè)問題,這個(gè)在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.
從上面也可以看到其實(shí)一個(gè)變量的更新由view到model和model到view不止$formatters和$parsers管道,那么還有哪些呢?
在查了一圈資料后找到一個(gè)很清晰的解釋:https://stackoverflow.com/que...,大家其實(shí)只需要看問題的回答,問題實(shí)在太長(zhǎng)了。。。
這個(gè)回答中有個(gè)demo鏈接,我copy了一下并做了寫小修改放在這個(gè)地址了:http://runjs.cn/code/qte0mm49,這個(gè)demo很清晰的顯示了變量更新的過程,細(xì)節(jié)就不再累述了,這里只把結(jié)果總結(jié)如下:
從model到view:
model值修改 ----> $formatters管道 ----> $render函數(shù) ----> $validators ----> $watch函數(shù)
從view到model:
view值修改 ----> $setViewValue函數(shù)----> $parsers管道 ----> $validators ----> $viewChangeListener函數(shù) ----> $watch函數(shù)
我們也可以直接調(diào)用$setViewValue函數(shù)去直接改變$viewValue 的值,流程會(huì)和上面一樣。
注意在使用$setViewValue時(shí)一定要警惕參數(shù)是引用變量的情況,這個(gè)坑在上文也已經(jīng)提到了。
本文沒有具體介紹$formatters 和 $parsers 管道,關(guān)于這部分可以參考文中給出的鏈接
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/107586.html
摘要:,的事件回調(diào)函數(shù)中調(diào)用的操作方法。以為例調(diào)用關(guān)系模式實(shí)際就是將中的改名為,調(diào)用過程基本一致,最大的改良是間的雙向綁定。和間,有一個(gè)對(duì)象,可以操作修改,使用。 參考:MVC,MVP 和 MVVM 的圖示 - 阮一峰http://www.ruanyifeng.com/blo...Web開發(fā)的MVVM模式http://www.cnblogs.com/dxy198...界面之下:還原真實(shí)的MV...
摘要:,的事件回調(diào)函數(shù)中調(diào)用的操作方法。以為例調(diào)用關(guān)系模式實(shí)際就是將中的改名為,調(diào)用過程基本一致,最大的改良是間的雙向綁定。和間,有一個(gè)對(duì)象,可以操作修改,使用。 參考:MVC,MVP 和 MVVM 的圖示 - 阮一峰http://www.ruanyifeng.com/blo...Web開發(fā)的MVVM模式http://www.cnblogs.com/dxy198...界面之下:還原真實(shí)的MV...
摘要:我們下面來看看的源碼這是其中一個(gè),在不同的指令下的代碼都不太一樣,但是其作用基本一致,但是從這里我們就可以看出的到底在干什么事了。 這篇文章是我兩年前在博客園寫的,現(xiàn)在移植過來,不過Angular 1.x 在國(guó)內(nèi)用的人已經(jīng)不多了,希望能幫助到有需要的人 在我開始著手 ngModel 的領(lǐng)域時(shí)候,有一個(gè)問題很令我糾結(jié),那就是 $render 到底是做什么的呢?查了很多資料都只是簡(jiǎn)單的描述...
摘要:它通過數(shù)據(jù)模型進(jìn)行鍵值綁定及事件處理,通過模型集合器提供一套豐富的用于枚舉功能,通過視圖來進(jìn)行事件處理及與現(xiàn)有的通過接口進(jìn)行交互。 本人兼職前端付費(fèi)技術(shù)顧問,如需幫助請(qǐng)加本人微信hawx1993或QQ345823102,非誠(chéng)勿擾 1.為初學(xué)前端而不知道怎么做項(xiàng)目的你指導(dǎo) 2.指導(dǎo)并扎實(shí)你的JavaScript基礎(chǔ) 3.幫你準(zhǔn)備面試并提供相關(guān)指導(dǎo)性意見 4.為你的前端之路提供極具建設(shè)性的...
摘要:的思想非常先進(jìn),摒棄了那種復(fù)雜的構(gòu)建模式,采用了組件化開方的方,那我們一起來看一看,一個(gè)基礎(chǔ)的組件是什么樣子的呢。 angular2的思想非常先進(jìn),摒棄了angular1那種復(fù)雜的構(gòu)建模式,采用了組件化開方的方,那我們一起來看一看,一個(gè)基礎(chǔ)的組件是什么樣子的呢。angular2-demoshowImg(http://static.xiaomo.info/images/angular.p...
閱讀 1261·2023-04-26 02:38
閱讀 944·2023-04-25 20:13
閱讀 3599·2021-11-19 11:31
閱讀 2403·2019-08-30 15:55
閱讀 2731·2019-08-30 14:11
閱讀 3171·2019-08-30 13:45
閱讀 1385·2019-08-29 18:41
閱讀 1158·2019-08-29 16:18