首頁  >  文章  >  web前端  >  angular1學習筆記,裡面有angularjs中的view model同步過程

angular1學習筆記,裡面有angularjs中的view model同步過程

寻∝梦
寻∝梦原創
2018-09-07 17:28:251343瀏覽

這算是一篇個人對angularjs的理解筆記吧,這裡有view model的同步過程,寫給大家看看吧,現在就讓我們一起進入本篇文章吧

事情起源於在專案中遇到的一個小問題:專案中需要一個輸入框輸入賣出產品數量,並且在使用者輸入後根據輸入資料計算手續費。很自然的我用了ng-model和ng-change,而且一般情況下沒什麼問題。問題是:輸入框下方還有一個按鈕是全部賣出,點選這個按鈕程式會自動設定賣出額。但實際上這時程式並沒有計算手續費。
經過排查並查閱文件之後,發現是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的監聽。所以當我們直接在js修改ng-model的變數時並不會觸發ng-change。
問題找到了,解決方案也不難,放棄ng-change,改用$watch就行了。
但是就這麼結束了嗎?一個變數從view變化開始到同步更新到model到底經歷了什麼?反過來呢,是一樣的嗎?
所以我又去看了看ng-model的源碼,並沒有什麼收穫,不過意外的了解到了這麼個點:
ng-change是在model值變化之前執行的。 ng-model原始碼中有這麼個函數:

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://php.cn/course/47.html

既然看原始碼沒什麼收穫,那就上網搜搜文章看看吧。這個過程中找到一篇很好的文章,這篇文章介紹了

$formatters,$parsers,$render以及$setViewValue。這裡就不再介紹了,如果需要學習,原文在這裡:http://php.cn/course/47.html

在學習$setViewValue時也發現一個很容易被坑的點:在呼叫$setViewValue時,如果參數是引用變量,那麼如果引用變數位址沒變,則這個變數被認為沒有改變,如var map = ['er', 'tr '];那麼map.pop();之後$setViewValue不認為map值改變了。關於這個具體可以看​​我對這個問題的回答。 (想看更多就到PHP中文網AngularJS開發手冊中學習)

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 Model will willnotngize that the object has changed and will not invoke the
$parsersand
$validators pipelines.

#從上面也可以看到其實一個變數的更新由view到model和model到view不只

$formatters$parsers管道,那麼還有哪些呢?

在查了一圈資料後找到一個很清楚的解釋:https://stackoverflow.com/que...,大家其實只需要看問題的回答,問題實在太長了。 。 。

這個回答中有個demo鏈接,我copy了一下並做了寫小修改放在這個地址了:http://php.cn/course/47.html,這個demo很清晰的顯示了變量更新的過程,細節就不再累述了,這裡只把結果總結如下:
從model到view:
model值修改---->
$formatters管道--- -> $render函數----> $validators ----> $watch函數

從view到model:

view值修改---->
$setViewValue函數----> $parsers管道----> $validators ----> $viewChangeListener函數----> $watch函數我們也可以直接呼叫
$setViewValue函數去直接改變$viewValue 的值,流程會跟上面一樣。 注意在使用
$setViewValue時一定要警惕參數是引用變數的情況,這個坑在上文也已經提到了。

本文沒有具體介紹

$formatters$parsers 管道,關於這部分可以參考文中給出的連結

好了,這篇文章到這就結束了(想看更多就到PHP中文網AngularJS使用手冊中學習),有問題的可以在下方留言提問。

#

以上是angular1學習筆記,裡面有angularjs中的view model同步過程的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn