2014-01-14 47 views
2

我最近更新了一個從Angular 1.2.0rc1到Angular 1.2.5的解決方案。AngularUI Select2 ajax:不更新ng-model的選擇

我們使用AngularUI爲下拉菜單提供Select2 ajax功能。在從Angular 1.2.0rc1更新之前,一切正常; Select2將處理ajax調用並加載下拉數據,並選擇一個對象將填充該表單元素。

現在我們已經更新到1.2.5,ajax功能仍在加載數據 - 但是做出選擇時不會使用ui-select2綁定更新附加到輸入的ng模型。因此,表單無法驗證(因爲該字段是必需的)並且用戶無法繼續。

我一直在尋找到這一點,一個可能的解決方案是重寫的解決方案使用常規選擇2下拉列表中,使用<select><option data-ng-repeat="each in myModel">標籤和採用了棱角分明的自己的AJAX功能將數據追加到myModel。不過,我預見到這個問題(處理滾動等),我正在尋找更簡單,更快捷的解決方案。

有沒有人遇到過這個問題?任何人都可以闡明這種情況嗎?

回答

2

在測試過程中,我發現我們在此表單輸入的模型上有一個$scope.watch。事實證明,手錶功能將運行三次 - 第一次,具有正確的對象值;第二次用字符串「Object object」作爲對象的表示;第三次,空值。我通過檢查newValue數據類型對此進行了修復 - 如果它是一個字符串,則將模型重置爲舊值。然而,儘管這很有效,但我仍然不確定爲什麼簡單地改變圖書館會導致這樣的迴歸。

如果我有時間,我打算嘗試用簡化的測試用例來重現這一點。

更新2:我發現this question,這解釋了這不起作用的根本原因。因此,看起來可以在指令上設置優先級並調用渲染函數。

代碼會像這樣:

angular.module('ui.select2', []).value('uiSelect2Config', {}).directive('uiSelect2', ['uiSelect2Config', '$timeout', 
    function (uiSelect2Config, $timeout) { 
     var options = {}; 
     if (uiSelect2Config) { 
      angular.extend(options, uiSelect2Config); 
     } 
     return { 
      require: 'ngModel', 
      priority: 1, // This fixed it. 
      compile: function (tElm, tAttrs) { 
       ...... 

我們用這個在我們的解決方案,雖然它並不完美(仍然有一些打嗝有數據綁定在某些情況下,選擇二愛,而不是返回對象的字符串出於某種原因),我們已經能夠使其工作。

更新:我想我在AngularUI的select2.js中發現了潛在的問題。

source code下面定義的指令進行選擇2的一部分convertToSelect2Model下:

if (controller) { 
    // Watch the model for programmatic changes 
    scope.$watch(tAttrs.ngModel, function (current, old) { 
     if (!current) { 
      return; 
     } 
     if (current === old) { 
      return; 
     } 
     controller.$render(); 
    }, true); 
    controller.$render = function() { 
     if (isSelect) { 
      elm.select2('val', controller.$viewValue); 
     } else { 
      if (opts.multiple) { 
       var viewValue = controller.$viewValue; 
       if (angular.isString(viewValue)) { 
        viewValue = viewValue.split(','); 
       } 
       elm.select2(
        'data', convertToSelect2Model(viewValue)); 
      } else { 
       if (angular.isObject(controller.$viewValue)) { 
        elm.select2('data', controller.$viewValue); 
       } else if (!controller.$viewValue) { 
        elm.select2('data', null); 
       } else { 
        elm.select2('val', controller.$viewValue); 
       } 
      } 
     } 
    }; 

這是一切都在老版本的角度好。但是,在Angular 1.2.5中,這是行不通的;該函數實際上已經由Angular定義,因此寫函數從不會被調用。將controller.$render函數重命名爲controller.$renderui修復了潛在的問題。這是我的解決辦法:

if (controller) { 
    controller.$renderui = function() { 
     if (isSelect) { 
      elm.select2('val', controller.$viewValue); 
     } else { 
      if (opts.multiple) { 
       elm.select2(
        'data', convertToSelect2Model(controller.$viewValue)); 
      } else { 
       if (angular.isObject(controller.$viewValue)) { 
        elm.select2('data', controller.$viewValue); 
       } else if (!controller.$viewValue) { 
        elm.select2('data', null); 
       } else { 
        elm.select2('val', controller.$viewValue); 
       } 
      } 
     } 
    }; 

    // Watch the model for programmatic changes 
    scope.$watch(tAttrs.ngModel, function (current, old) { 
     if (!current) { 
      return 
     } 
     if (current == old) { 
      return 
     } 
     controller.$renderui(); 
    }, true) 

這個固定了很多,我有選擇二跑進問題(在我的項目中使用),並結合到NG-模型(和現在一樣,選擇二將正確更新時NG-模型更改),包括我原來的問題。

TLDR:AngularUI select2嘗試定義controller.$render,但該函數已由Angular 1.2.5內部定義,並試圖重新定義它似乎不起作用。重命名函數似乎可以解決問題。

我希望這可以幫助別人。