Làm cách nào tôi có thể đưa Knockout JS vào liên kết dữ liệu trên phím nhấn thay vì mất tập trung?


191

Ví dụ này về js loại trực tiếp hoạt động để khi bạn chỉnh sửa một trường và nhấn TAB, dữ liệu viewmodel và do đó văn bản bên dưới các trường được cập nhật.

Làm cách nào để thay đổi mã này để dữ liệu viewmodel được cập nhật mỗi lần nhấn phím?

văn bản thay thế

<!doctype html>
<html>
    <title>knockout js</title>
    <head>
        <script type="text/javascript" src="js/knockout-1.1.1.debug.js"></script>
        <script type="text/javascript">
        window.onload= function() {

            var viewModel = {
                firstName : ko.observable("Jim"),
                lastName : ko.observable("Smith")
            };
            viewModel.fullName = ko.dependentObservable(function () {
                return viewModel.firstName() + " " + viewModel.lastName();
            });

            ko.applyBindings(viewModel);
       }
        </script>
    </head>
    <body>
        <p>First name: <input data-bind="value: firstName" /></p>
        <p>Last name: <input data-bind="value: lastName" /></p>
        <h2>Hello, <span data-bind="text: fullName"> </span>!</h2>
    </body>
</html>

9
Trong KO 3.2, không cần phải thực hiện tất cả các cách giải quyết này: stackoverflow.com/a/25493265/1090562
Salvador Dali

Salvador là chính xác - nó tự động làm trong phiên bản mới nhất.
vapcguy

Câu trả lời:


299
<body>
        <p>First name: <input data-bind="value: firstName, valueUpdate: 'afterkeydown'" /></p>
        <p>Last name: <input data-bind="value: lastName, valueUpdate: 'afterkeydown'" /></p>
        <h2>Hello, <span data-bind="text: fullName"> </span>!</h2>
</body>

Từ tài liệu

Thông số bổ sung

  • valueUpdate

    Nếu ràng buộc của bạn cũng bao gồm một tham số gọi là valueUpdate, thì điều này xác định sự kiện trình duyệt KO nên sử dụng để phát hiện các thay đổi. Các giá trị chuỗi sau đây là các lựa chọn hữu ích nhất:

    • "thay đổi" (mặc định) - cập nhật mô hình chế độ xem của bạn khi người dùng di chuyển tiêu điểm sang một điều khiển khác hoặc trong trường hợp các yếu tố, ngay sau khi có bất kỳ thay đổi nào

    • "keyup" - cập nhật mô hình xem của bạn khi người dùng phát hành khóa

    • "nhấn phím" - cập nhật mô hình chế độ xem của bạn khi người dùng đã nhập khóa. Không giống như keyup, bản cập nhật này lặp đi lặp lại trong khi người dùng giữ phím

    • "afterkeydown" - cập nhật mô hình chế độ xem của bạn ngay khi người dùng bắt đầu nhập một ký tự. Điều này hoạt động bằng cách bắt sự kiện keydown của trình duyệt và xử lý sự kiện không đồng bộ.

Trong số các tùy chọn này, "afterkeydown" là lựa chọn tốt nhất nếu bạn muốn giữ cho mô hình xem của mình được cập nhật theo thời gian thực.


9
từ các tài liệu trong knout.j.j
John Wright

4
Có cách nào để lấy valueUpdate: 'afterkeydown' làm mặc định không?
Aaron Shafovaloff

2
đối với một số hộp đầu vào, trình duyệt hiển thị các giá trị "tự động điền" (như nếu trường đầu vào được đặt tên là "tên gọi"). chọn từ tự động điền không hoạt động với "afterkeydown". Có cách nào để bắt cái này không?
Anton

2
@Anton Ngoài các giá trị tự động điền, còn có các nhấp chuột trên màn hình và các sự kiện dán chuột cần được bắt. Sử dụng afterkeydownlà một giải pháp tồi.
John Kurlak

2
Tác giả của câu trả lời này, vui lòng cập nhật để bao gồm câu trả lời của Salvador Dali, textInput được thêm vào ngày 3.2 là một giải pháp tốt hơn vì nó có khả năng tương thích tốt hơn với các trình duyệt di động (những thứ như tự động hoàn thành công việc tốt hơn)
Michael Crook

85

Trong phiên bản 3.2, bạn chỉ cần sử dụng ràng buộc textinput. :

<input data-bind="textInput: userName" />

Nó thực hiện hai điều quan trọng:

  • cập nhật ngay lập tức
  • xử lý các khác biệt của trình duyệt để cắt, kéo, tự động hoàn thành ...

Vì vậy, không cần thêm các mô-đun, điều khiển tùy chỉnh và những thứ khác.


Điều này hoạt động thực sự tốt và chính xác là những gì tôi cần để thay thế giá trị: trường, valueUpdate: 'thay đổi đầu vào' mà tôi đã có tất cả thông qua ứng dụng của mình ... :) cảm ơn.
Tod Thomson

Có cách nào để ghi lại sự kiện khi người dùng nhấp vào biểu tượng 'x' trên trường nhập liệu tìm kiếm HTML5 mới và hoạt động như trong trường hợp đầu vào trống không?
Codrina Valo

35

Nếu bạn muốn nó thực hiện cập nhật trên afterkeydown"theo mặc định", bạn có thể đưa valueUpdateliên kết vào valuetrình xử lý ràng buộc. Chỉ cần cung cấp một cái mới allBindingsAccessorcho trình xử lý để sử dụng bao gồm afterkeydown.

(function () {
    var valueHandler = ko.bindingHandlers.value;
    var getInjectValueUpdate = function (allBindingsAccessor) {
        var AFTERKEYDOWN = 'afterkeydown';
        return function () {
            var allBindings = ko.utils.extend({}, allBindingsAccessor()),
                valueUpdate = allBindings.valueUpdate;

            if (valueUpdate === undefined) {
                return ko.utils.extend(allBindings, { valueUpdate: AFTERKEYDOWN });
            } else if (typeof valueUpdate === 'string' && valueUpdate !== AFTERKEYDOWN) {
                return ko.utils.extend(allBindings, { valueUpdate: [valueUpdate, AFTERKEYDOWN] });
            } else if (typeof valueUpdate === 'array' && ko.utils.arrayIndexOf(valueUpdate, AFTERKEYDOWN) === -1) {
                valueUpdate = ko.utils.arrayPushAll([AFTERKEYDOWN], valueUpdate);
                return ko.utils.extend(allBindings, {valueUpdate: valueUpdate});
            }
            return allBindings;
        };
    };
    ko.bindingHandlers.value = {
        // only needed for init
        'init': function (element, valueAccessor, allBindingsAccessor) {
            allBindingsAccessor = getInjectValueUpdate(allBindingsAccessor);
            return valueHandler.init(element, valueAccessor, allBindingsAccessor);
        },
        'update': valueHandler.update
    };
} ());

Nếu bạn không thoải mái "ghi đè" valueràng buộc, bạn có thể cung cấp cho tùy chỉnh ghi đè ràng buộc một tên khác và sử dụng trình xử lý ràng buộc đó.

ko.bindingHandlers.realtimeValue = { 'init':..., 'update':... };

bản giới thiệu

Một giải pháp như thế này sẽ phù hợp với Knockout phiên bản 2.x. Nhóm Knockout đã đưa ra một ràng buộc hoàn chỉnh hơn cho các đầu vào giống như văn bản thông qua liên kết textInput trong Knockout phiên bản 3 trở lên. Nó được thiết kế để xử lý tất cả các phương thức nhập văn bản cho nhập văn bản và textarea. Nó thậm chí sẽ xử lý cập nhật theo thời gian thực, điều này làm cho phương pháp này trở nên lỗi thời.


2
Cách này làm cho đánh dấu của tôi gọn gàng hơn một chút. Ngoài ra, ngoài các sự kiện 'afterkeydown', 'đầu vào' và 'dán' có thể được thêm vào để xử lý các hành động dán / kéo và thả.
bob

Trong giải pháp trên tôi nghĩ rằng "typeof valueUpdated === 'mảng'" cần được thay thế bằng "Object.prototype.toString.call (valueUpdate) === '[Array Array]'". Xem stackoverflow.com/questions/4775722/ từ
daveywc

20

Câu trả lời của Jeff Mercado là tuyệt vời, nhưng không may bị phá vỡ với Knockout 3.

Nhưng tôi đã tìm thấy câu trả lời được đề xuất bởi các nhà phát triển trong khi thực hiện các thay đổi của Knockout 3. Xem các bình luận dưới cùng tại https://github.com/knockout/knockout/pull/932 . Mã của họ:

//automatically add valueUpdate="afterkeydown" on every value binding
(function () {
    var getInjectValueUpdate = function (allBindings) {
        return {
            has: function (bindingKey) {
                return (bindingKey == 'valueUpdate') || allBindings.has(bindingKey);
            },
            get: function (bindingKey) {
                var binding = allBindings.get(bindingKey);
                if (bindingKey == 'valueUpdate') {
                    binding = binding ? [].concat(binding, 'afterkeydown') : 'afterkeydown';
                }
                return binding;
            }
        };
    };

    var valueInitHandler = ko.bindingHandlers.value.init;
    ko.bindingHandlers.value.init = function (element, valueAccessor, allBindings, viewModel, bindingContext) {
        return valueInitHandler(element, valueAccessor, getInjectValueUpdate(allBindings), viewModel, bindingContext);
    };
}());

http://jsfiddle.net/mbest/GKJnt/

Chỉnh sửa Ko 3.2.0 bây giờ có một giải pháp hoàn chỉnh hơn với ràng buộc "textInput" mới. Xem câu trả lời của SalvidorDali


1
Cảm ơn đã cập nhật câu trả lời lên 3.0!
Graham T

@GrahamT trong KO 3.2 bạn thậm chí không cần nó. Nó chỉ là một dòng
Salvador Dali

Rất tốt cho những người trong chúng tôi trên KO 3.2, những người không biết về TextInput khi chúng tôi bắt đầu và không thể cập nhật mọi đầu vào trong toàn hệ thống!
cscott530
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.