angularJs中ngModel的坑


  angular中指令被用的最多的除了ng-repeat之外就非他莫屬了吧,由於各種業務的需求,我們經常需要去寫一些繼承ngModel的指令,來滿足各種奇葩需求,最多的莫過於表單的驗證啦,另外你在封裝一些jquery插件的時候,也是需要繼承ngModel的,最典型的莫過於 datepicker、fileUpload等等。

  但是ngModel本身其實有很多坑,在這里分享給大家,如果大家又遇到其他問題,歡迎補充:

  首先我們要知道一些概念的東西,這里我就不占篇幅了,不了解的可以先去看看這篇文章:

    http://www.cnblogs.com/liulangmao/p/4110137.html  

  在這里,我基本分為兩種問題,一種是viewValue和modelValue不同的問題,另一種是管道問題

    第一種:viewValue和modelValue不同的問題

      1.viewValue想變成modelValue

      2.modelValue想變成ViewValue        

      3.moduleValue想和viewModel不一樣

      4.viewModel和DOM元素的值不一樣

      要想解決這些問題,我們先來了解一些$apply的一個問題,那就是執行$apply之后數據是以什么為主的

      ①viewValue -> modelValue

      ②modelValue -> viewValue,於是我們寫了下面這個指令      

 <input type="text" ng-model="vm.modelTest" model-test>  
.directive('modelTest',function(){
        return {
            require : 'ngModel',
            link : function(scope,iElm,iAttrs,ngModelCtrl){
                iElm.on('mouseenter',function(){
                    console.info("打印出更改之后,沒有執行$apply的值")
                    console.log(ngModelCtrl);
                    
                    //更改modelValue的值
                    ngModelCtrl.$modelValue = "test change";
                    
                    console.info("打印出更改之后,沒有執行$apply的值")
                    console.log(ngModelCtrl);
                    
                    //執行$apply
                    scope.$apply();
                    
                    console.info("打印出更改之后,執行$apply的值")
                    console.log(ngModelCtrl);
                })                  
            }
        }
    })

    從上面的指令,我們不難得出一個比較武斷的結論 $apply會根據viewValue的值而改變modelValue的值,也就是modelValue -> viewValue,那么,我們可以開始解決我們的問題了。    

      1.viewValue想變成modelValue

        這種情況很少, 但是如果你在jq的操作就可能發生這種需求,一般依然還是$apply讓model的值重新更新,使用了$apply就會觸發$render()函數,因為modelValue的變化,會導致$render觸發

      2.modelValue想變成ViewValue (看了上面的實驗,我想你應該懂了,直接使用$apply)       

      3.moduleValue想和viewModel不一樣

        一般情況都會使用管道去解決,但是有個其他思路可以提供給大家,下面這段代碼是在國外看到的,覺得挺不錯的,效果大家可以去嘗試下,將model的值變成數組。

ngModelCtrl.$viewChangeListeners.push(function(){
                                 $parse(iAttrs.ngModel).assign(scope, ngModelCtrl.$viewValue.split(',')); 
                            });

    第二種:管道問題

      管道是什么呢,在ngModel里面其實就是view視圖和model視圖數據交互的時候需要經過的數組或對象,這個數組或對象由方法組成,每次經過都會執行數組里面的方法,並返回結果。一共有四種管道

      $formatters :它是model視圖轉向view視圖的管道(數組),model的值會經過他才轉變成view視圖的值,另外它的調用順序是最特別的,從后往前調用,,越在數組后面,越早調用。

      $parsers : 它正好是跟$formatters相反,是view視圖轉向model視圖的管道(數組),view的值會經過他才轉變成model視圖的值,在1.2.x(兼容IE8)之前一般我們會在這里實現或擴展驗證功能

      $validators:這是在1.3.x之后出現的管道(json對象),來幫助我們實現和擴展驗證功能的,當我們進入$parsers的同時,同時也會進入$validators,在這里我貼段源碼(驗證required)給大家看看,我想大家應該能理解這個管道的功能

ctrl.$validators.required = function(modelValue, viewValue) {
        return !attr.required || !ctrl.$isEmpty(viewValue);
      };

      $asyncValidators :功能與$validators相似,不同的是他可以實現異步驗證,你可以在管道內部執行異步處理,會在結果返回之后,才去設置驗證結果,這是個大課題,我看到有人討論過,我也就不詳細講了http://www.cnblogs.com/liulangmao/p/4118868.html可以進去這個博客看看。

      好了,ngModel的一些東西基本已將講完了,另外還有一些就不仔細去說了,我的博客里面還有一篇關於$render的詳解,有興趣的可以了解下。

      此帖是原創,轉載請注明


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM