Làm cách nào để thực hiện lọc hai chiều trong AngularJS?


124

Một trong những điều thú vị mà AngularJS có thể làm là áp dụng bộ lọc cho một biểu thức liên kết dữ liệu cụ thể, đây là một cách thuận tiện để áp dụng, chẳng hạn như tiền tệ theo văn hóa cụ thể hoặc định dạng ngày của các thuộc tính của mô hình. Nó cũng rất tuyệt khi có các thuộc tính được tính toán trên phạm vi. Vấn đề là cả hai tính năng này đều không hoạt động với các tình huống kết hợp dữ liệu hai chiều - chỉ kết hợp dữ liệu một chiều từ phạm vi đến chế độ xem. Đây dường như là một thiếu sót rõ ràng trong một thư viện tuyệt vời khác - hay tôi đang thiếu thứ gì đó?

Trong KnockoutJS , tôi có thể tạo một thuộc tính tính toán đọc / ghi, cho phép tôi chỉ định một cặp hàm, một hàm được gọi để lấy giá trị của thuộc tính và một hàm được gọi khi thuộc tính được đặt. Điều này cho phép tôi triển khai, ví dụ: đầu vào nhận biết văn hóa - cho phép người dùng nhập "$ 1,24" và phân tích cú pháp đó thành một float trong ViewModel và có những thay đổi trong ViewModel được phản ánh trong đầu vào.

Điều gần nhất mà tôi có thể tìm thấy tương tự như điều này là việc sử dụng $scope.$watch(propertyName, functionOrNGExpression);This cho phép tôi có một hàm được gọi khi một thuộc tính trong $scopethay đổi. Nhưng điều này không giải quyết được, ví dụ, vấn đề đầu vào nhận thức về văn hóa. Lưu ý các vấn đề khi tôi cố gắng sửa đổi thuộc $watchedtính trong $watchchính phương thức:

$scope.$watch("property", function (newValue, oldValue) {
    $scope.outputMessage = "oldValue: " + oldValue + " newValue: " + newValue;
    $scope.property = Globalize.parseFloat(newValue);
});

( http://jsfiddle.net/gyZH8/2/ )

Phần tử đầu vào rất khó hiểu khi người dùng bắt đầu nhập. Tôi đã cải thiện nó bằng cách chia thuộc tính thành hai thuộc tính, một cho giá trị chưa được phân tích cú pháp và một cho giá trị đã phân tích cú pháp:

$scope.visibleProperty= 0.0;
$scope.hiddenProperty = 0.0;
$scope.$watch("visibleProperty", function (newValue, oldValue) {
    $scope.outputMessage = "oldValue: " + oldValue + " newValue: " + newValue;
    $scope.hiddenProperty = Globalize.parseFloat(newValue);
});

( http://jsfiddle.net/XkPNv/1/ )

Đây là một cải tiến so với phiên bản đầu tiên, nhưng dài dòng hơn một chút và lưu ý rằng vẫn còn một vấn đề về thuộc parsedValuetính của phạm vi thay đổi (nhập một cái gì đó vào đầu vào thứ hai, điều này sẽ thay đổi parsedValuetrực tiếp. Lưu ý rằng đầu vào trên cùng không cập nhật). Điều này có thể xảy ra từ hành động của bộ điều khiển hoặc do tải dữ liệu từ một dịch vụ dữ liệu.

Có cách nào dễ dàng hơn để thực hiện kịch bản này bằng AngularJS không? Tôi có thiếu một số chức năng trong tài liệu không?

Câu trả lời:


231

Hóa ra có một giải pháp rất hữu ích cho vấn đề này, nhưng nó không được ghi chép đầy đủ.

Định dạng giá trị mô hình để hiển thị có thể được xử lý bởi |toán tử và một góc formatter. Nó chỉ ra rằng ngModel không chỉ có danh sách các bộ định dạng mà còn có một danh sách các bộ phân tích cú pháp.

1. Sử dụng ng-modelđể tạo liên kết dữ liệu hai chiều

<input type="text" ng-model="foo.bar"></input>

2. Tạo một chỉ thị trong mô-đun góc của bạn sẽ được áp dụng cho cùng một phần tử và điều đó phụ thuộc vào ngModelbộ điều khiển

module.directive('lowercase', function() {
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function(scope, element, attr, ngModel) {
            ...
        }
    };
});

3. Trong linkphương pháp này, hãy thêm bộ chuyển đổi tùy chỉnh của bạn vào ngModelbộ điều khiển

function fromUser(text) {
    return (text || '').toUpperCase();
}

function toUser(text) {
    return (text || '').toLowerCase();
}
ngModel.$parsers.push(fromUser);
ngModel.$formatters.push(toUser);

4. Thêm chỉ thị mới của bạn vào cùng một phần tử đã có ngModel

<input type="text" lowercase ng-model="foo.bar"></input>

Dưới đây là một ví dụ làm việc chuyển đổi văn bản thành chữ thường inputvà trở lại chữ hoa trong mô hình

Các tài liệu API cho Controller mẫu cũng có một giải thích ngắn gọn và tổng quan về các phương pháp có sẵn khác.


Có lý do nào bạn sử dụng "ngModel" làm tên cho tham số thứ tư trong hàm liên kết của mình không? Đó không phải chỉ là một bộ điều khiển chung cho chỉ thị về cơ bản không liên quan gì đến thuộc tính ngModel? (Vẫn học tập góc ở đây vì vậy tôi có thể là hoàn toàn sai.)
Drew Miller

7
Vì "request: 'ngModel'", tham số thứ 4 của hàm liên kết sẽ là bộ điều khiển của chỉ thị ngModel - tức là bộ điều khiển của foo.bar, là một phiên bản của ngModelController . Bạn có thể đặt tên cho tham số thứ 4 bất cứ điều gì bạn muốn. (Tôi sẽ đặt tên cho nó ngModelCtrl.)
Mark Rajcok 19/12/12

8
Kỹ thuật này được ghi lại tại docs.angularjs.org/guide/forms , trong phần Xác thực Tùy chỉnh.
Nikhil Dabas

1
@Mark Rajcok trong fiddle được cung cấp, trong khi nhấp vào Tải dữ liệu - tất cả đều là chữ thường, tôi dự kiến ​​giá trị mô hình sẽ ở dạng TẤT CẢ CÁC CHỮ HOA, nhưng giá trị mô hình nhỏ. Bạn có thể làm ơn. giải thích tại sao, và làm thế nào để làm cho mô hình luôn TRÊN CAPS
Rajkamal Subramanian

1
@rajkamal, vì loadData2 () sửa đổi $scopetrực tiếp, đó là những gì mô hình sẽ được đặt thành ... cho đến khi người dùng tương tác với hộp văn bản. Tại thời điểm đó, bất kỳ trình phân tích cú pháp nào sau đó có thể ảnh hưởng đến giá trị mô hình. Ngoài trình phân tích cú pháp, bạn có thể thêm $ watch vào bộ điều khiển của mình để biến đổi giá trị mô hình.
Mark Rajcok
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.