2015-07-10 63 views
14

我正試圖在不同的瀏覽器中處理ngModel的不同行爲。ngModel - 如何處理不同瀏覽器中的不同行爲?

我的指令包裝了jqueryUI的自動完成功能,在其select事件中它調用ngModel.$setViewValue(selectedItem.id)。自動完成允許用戶通過鼠標點擊或按鍵盤上的enter來選擇項目。

如果建議產品:

{ 
    "name": "Apple", 
    "id": "1000" 
} 

選擇它後,我想到,ngModel值將所選項目的id - 1000

  • 在Chrome中它工作正常 - 它集$viewValue$modelValue正確($modelValue=1000)。

  • 在Firefox它設置模型在Chrome($modelValue=1000),但是當我點擊別的地方 - 使模糊(當時的瀏覽器可能觸發change事件),模型的變化和它變得一樣可見的輸入值($modelValue='Apple')。

  • 在IE 11中,只有當我用鼠標單擊選擇項目時,它纔會設置模型正確。如果我按enter選擇它,模型變得可見的輸入值($modelValue='Apple'

這裏是plunkr:http://plnkr.co/edit/o2Jkgprf8EakGqnpu22Y?p=preview

我想達到在每個瀏覽器相同的行爲。如何處理這個問題?

+0

我認爲使用兩種截然不同的模型會更好,一種是保存解析的異步值(可能是私有的),另一種是用戶用來輸入查詢(public)的模型。就目前而言,當你輸入一個完整的虛假名稱(不在水果列表中)時,這將成爲模型值。當你期望它是一個ID時,這可能不會有什麼幫助。 – Yoshi

+0

@Yoshi,你剛纔提到它只是一個驗證改進 - 用戶將不能輸入id以外的內容,但它不能解決問題。 (或者我不知道如何正確實施)。隨着你的提示它會是這樣的:http://plnkr.co/edit/7nCAEhIXX2wGNR18eRqk。 '$ modelValue = null'爲僞造的名字,但是在firefox解析器函數仍然在blur上再次運行,所以我失去了我的選擇值。 – akn

+0

如果是單獨的事件,您可以嘗試使用['ngModelOptions.updateOn'](https://docs.angularjs.org/api/ng/directive/ngModelOptions)。 – Yoshi

回答

1

好吧,我想我已經做到了。該解決方案基於Yoshi's comment,它使用本地模型來保存選定的數據。

當用戶選擇一些東西時,本地模型設置爲選中Object並且$viewValue被設置爲所選項目的文本值。然後解析器將id本地模型的屬性設置爲$modelValue

select: function(event, ui) { 
    if(ui.item && ui.item.data){ 
    model = ui.item.data 
    ngModel.$setViewValue(model.name); 
    scope.$apply(); 
    } 
} 

ngModel.$parsers.push(function(value) { 
    if(_.isObject(model) && value!==model.name){ 
    model = value; 
    return model; 
    } 
    return model.id; 
}); 

解析器函數也是一個重要的事情。因爲它是在用戶鍵入內容或在事件(這是Firefox中的問題!)時運行的,所以它會檢查該值是否與當前本地模型的文本值相同,如果不相同,則會將本地模型更改爲此值。這意味着如果解析器函數運行的是change,則事件值將與文本值相同,因此$modelValue不會更改,但如果用戶輸入某個模型更新爲輸入值(它將變爲String)。

驗證器功能檢查本地模型是否爲Object。如果不是,則表示該字段無效,因此默認情況下它的$modelValue消失。

這裏是plunkr: http://plnkr.co/edit/2ZkXFvgLIwDljfJoyeJ1?p=preview

(在格式化功能我回到那個什麼來,所以$viewValue是暫時的Object但隨後$render方法我稱之爲$setViewValue設置$viewValue$modelValue正確的,因此它成爲String我聽說$setViewValue不應該在$render方法中運行,但是當有東西來自外部時,我沒有看到其他方式來設置正確的$modelValue)。

2

這似乎與http://bugs.jqueryui.com/ticket/8878

正如上面的鏈接中指出,觸發僅在Firefox,而不是在Chrome的變化事件。所以在你的情況下,$ setViewValue在外部點擊並且模型值被設置爲「Apple」時再次被觸發。

有自動完成jQuery UI部件的變化回調。要處理這兩種情況/瀏覽器可能是你必須明確地設置視圖值在這個回調(和它的工作)。

http://plnkr.co/edit/GFxhzwieBJTSL8zjSPSZ?p=preview

link: function(scope, elem, attrs, ngModel) { 
     elem.on('change', function(){ 
     // This will not be printed in Chrome and only on firefox 
     console.log('change'); 
    }); 


    select: function(event, ui) { 
     ngModel.$setViewValue(ui.item.data.id); 
     scope.$apply(); 
    }, 
    // To handle firefox browser were change event is triggered 
    // when clicked outside/blur 
    change: function(event, ui) { 
     ngModel.$setViewValue(ui.item.data.id); 
     scope.$apply(); 
    } 
+0

謝謝,這不是完美的解決方案,但它可能會有所幫助。另外,它不能解決IE中輸入鍵問題。 – akn

0

我曾與ngModelController$setViewValue similiar打架。

最終我尋找替代解決方案。 我發現的一種方法很好,就是創建一個新元素作爲組件指令,其中包含輸入標籤作爲transcluded元素。

app.directive('fruitAutocomplete', function($http) { 
    return { 
    restrict: 'E', 
    require: 'ngModel', 
    transclude: true, 
    template: '<ng-transclude></ng-transclude>', 
    link: function(scope, elem, attrs, ngModelController) { 
     var $input = elem.find('input'); 

     $input.autocomplete({ 
     ... 
     }); 
    } 
    } 
}) 

在HTML:

<fruit-autocomplete name="fruit" ng-model="model.fruit"> 
    <input ng-disabled="inputDisabled" placeholder="input fruit"/> 
</fruit-autocomplete> 

下面是一個工作Plunker

有了這個建議的解決方案,您可以隔離ngModelController和jQueryUI的模式相互影響,以自己的定製元素,它不干擾「正常」<input>標籤,並且您不擔心jQueryUI錯誤。

通過使用<input>標籤,你仍然可以從大多數角度輸入好東西受益像ng-disabledplaceholder等transcluded元素...

+0

在此解決方案中,您失去了許多默認功能。例如。你不能設置'佔位符',你不能使用'ng-change'或'ng-disabled'。如果你想使用你的指令來處理真正的特定情況,可能會沒問題,但是如果你正在構建可用於大型應用程序的可重用指令,那就沒問題了) – akn

+0

接受挑戰! 請考慮我使用transclusion更新的答案。 – DanEEStar

相關問題