2015-07-10 20 views
14

Tôi đang cố xử lý các hành vi khác nhau của ngModel trong các trình duyệt khác nhau.ngModel - Cách xử lý hành vi khác nhau của nó trong các trình duyệt khác nhau?

Chỉ thị của tôi kết thúc tốt đẹp jqueryUI tự động hoàn thành và trên sự kiện select của nó gọi là ngModel.$setViewValue(selectedItem.id). Tự động hoàn tất cho phép người dùng chọn mục bằng cách nhấp chuột hoặc bằng cách nhấn enter trên bàn phím.

Nếu mục được đề xuất là:

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

Tôi hy vọng sau khi chọn nó, giá trị ngModel sẽ được lựa chọn item của id-1000.

  • Trong Chrome nó hoạt động OK - nó đặt $viewValue$modelValue một cách chính xác ($modelValue=1000).

  • Trong Firefox nó đặt mô hình như trong Chrome ($modelValue=1000), nhưng khi tôi bấm một nơi khác - làm mờ (sau đó trình duyệt có thể bắn change sự kiện), thay đổi mô hình và nó trở nên giống như giá trị đầu vào có thể nhìn thấy ($modelValue='Apple').

  • Trong IE 11, nó chỉ đặt đúng mô hình khi tôi chọn mục có nhấp chuột. Nếu tôi chọn nó bằng cách nhấn enter, mô hình trở nên giá trị đầu vào có thể nhìn thấy ($modelValue='Apple')

Đây là plunkr: http://plnkr.co/edit/o2Jkgprf8EakGqnpu22Y?p=preview

Tôi muốn để đạt được hành vi tương tự ở mọi trình duyệt. Làm thế nào để đối phó với những vấn đề đó?

+0

Tôi nghĩ bạn nên sử dụng hai mô hình riêng biệt, một mô hình giữ giá trị không đồng bộ được giải quyết (có thể là riêng tư) và một người dùng sử dụng để nhập truy vấn (công khai). Khi nó đứng, khi một loại trong một tên không có thật hoàn chỉnh (một trong đó không phải là trong danh sách các loại trái cây), thì đây sẽ là giá trị mô hình. Mà có lẽ là không thực sự hữu ích khi bạn mong đợi nó là một ID. – Yoshi

+0

@Yoshi, Đó là những gì bạn đã đề cập nó chỉ là một cải tiến xác nhận - người dùng sẽ không thể gõ một cái gì đó khác hơn là id, nhưng nó không giải quyết được vấn đề. (Hoặc tôi không biết làm thế nào để thực hiện nó đúng cách). Với gợi ý của bạn, nó sẽ là một cái gì đó như thế: http://plnkr.co/edit/7nCAEhIXX2wGNR18eRqk. '$ modelValue = null' cho tên không có thật, nhưng trong hàm phân tích cú pháp firefox vẫn chạy lại trên blur, vì vậy tôi mất giá trị đã chọn. – akn

+0

Nếu đó là sự kiện một mình, bạn có thể thử sử dụng ['ngModelOptions.updateOn'] (https://docs.angularjs.org/api/ng/directive/ngModelOptions). – Yoshi

Trả lời

1

Ok, tôi nghĩ rằng tôi đã thực hiện nó. Giải pháp dựa trên Yoshi's comment và sử dụng mô hình cục bộ để giữ dữ liệu được chọn.

Khi người dùng chọn thứ gì đó, mô hình cục bộ được đặt thành Object$viewValue được chọn được đặt thành giá trị văn bản của mục đã chọn. Sau đó, trình phân tích cú pháp đặt id thuộc tính của mô hình địa phương là $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; 
}); 

Chức năng trình phân tích cú pháp cũng là một điều quan trọng. Bởi vì nó chạy khi người dùng gõ một cái gì đó hoặc trên sự kiện change (đó là vấn đề trong firefox!), Nó sẽ kiểm tra nếu giá trị giống như giá trị văn bản của mô hình cục bộ hiện tại, và nếu không thay đổi mô hình cục bộ thành giá trị này. Nó có nghĩa là nếu hàm phân tích cú pháp được chạy bởi change giá trị sự kiện sẽ giống như giá trị văn bản, vì vậy $modelValue không thay đổi, nhưng nếu người dùng nhập mô hình nào đó được cập nhật thành giá trị đã nhập (nó sẽ trở thành String).

Chức năng xác thực kiểm tra xem mô hình địa phương có là Object hay không. Nếu không có nghĩa là trường đó không hợp lệ, theo mặc định, $modelValue biến mất.

Đây là plunkr: http://plnkr.co/edit/2ZkXFvgLIwDljfJoyeJ1?p=preview

(Trong chức năng định dạng tôi trở lại rằng điều gì sẽ đến, vì vậy $viewValue tạm thời một Object nhưng sau đó trong $render phương pháp tôi gọi $setViewValue thiết $viewValue$modelValue một cách chính xác, vì vậy nó trở thành String Tôi nghe thấy $setViewValue không nên chạy theo phương thức $render, nhưng tôi không thấy cách khác để đặt chính xác $modelValue khi có gì đó từ bên ngoài).

2

này dường như có liên quan đến http://bugs.jqueryui.com/ticket/8878

Như đã chỉ ra trong liên kết ở trên, sự kiện thay đổi được kích hoạt chỉ trong Firefox và không có trong Chrome. Vì vậy, trong trường hợp của bạn, $ setViewValue lại được kích hoạt khi được nhấp vào bên ngoài và giá trị mô hình được đặt thành "Apple".

Có thay đổi gọi lại cho tiện ích jquery ui tự động hoàn thành. Để xử lý cả hai trường hợp/trình duyệt có thể bạn sẽ phải đặt lại giá trị xem một cách rõ ràng trên cuộc gọi này trở lại (và nó hoạt động).

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

Cảm ơn, nó không phải là giải pháp hoàn hảo, nhưng nó có thể giúp đỡ. Ngoài ra, nó không giải quyết được vấn đề với khóa 'enter' trong IE. – akn

0

tôi đã chiến đấu tương tự với ngModelController$setViewValue.

Cuối cùng tôi đã tìm các giải pháp thay thế. Một cách tiếp cận mà tôi đã tìm thấy hoạt động khá tốt là tạo một phần tử mới làm chỉ thị thành phần bao gồm thẻ đầu vào như một phần tử được nhúng.

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({ 
     ... 
     }); 
    } 
    } 
}) 

Trong HTML:

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

Dưới đây là một Plunker

làm việc Với giải pháp đề xuất này bạn có thể cô lập các ngModelController và phương thức tương jQueryUI đến yếu tố tùy chỉnh riêng của mình và nó không can thiệp vào thẻ "bình thường" <input> và bạn không lo ngại về lỗi jQueryUI.

Bằng việc sử dụng thẻ <input> như yếu tố nhúng bạn vẫn có thể được hưởng lợi từ hầu hết các goodies đầu vào góc như ng-disabled, placeholder, vv ...

+0

Trong giải pháp này, bạn mất nhiều chức năng mặc định. Ví dụ. Bạn không thể đặt 'placeholder', bạn không thể sử dụng' ng-change' hoặc 'ng-disabled'. Nó 'có thể là ok khi bạn muốn sử dụng chỉ thị của bạn cho các trường hợp thực sự cụ thể, nhưng không phải nếu bạn đang xây dựng chỉ thị tái sử dụng sẽ được sử dụng trong ứng dụng lớn;) – akn

+0

Thách thức được chấp nhận! Vui lòng xem xét câu trả lời cập nhật của tôi bằng cách sử dụng tính năng chuyển đổi. – DanEEStar

Các vấn đề liên quan