ฉันจะทำให้ Knockout JS ไปยัง data-bind บน keypress แทนการสูญเสียโฟกัส


191

ตัวอย่างของสิ่งที่น่าพิศวง jsทำงานเมื่อคุณแก้ไขฟิลด์และกด TAB ข้อมูล viewmodel และด้วยเหตุนี้ข้อความด้านล่างของฟิลด์จึงถูกอัพเดต

ฉันจะเปลี่ยนรหัสนี้เพื่อให้ข้อมูลมุมมองโมเดลได้รับการอัปเดตทุกปุ่มกดได้อย่างไร

ข้อความแสดงแทน

<!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
ใน KO 3.2 ไม่จำเป็นต้องแก้ไขปัญหาเหล่านี้ทั้งหมด: stackoverflow.com/a/25493265/1090562
Salvador Dali

ซัลวาดอร์นั้นถูกต้อง - มันทำโดยอัตโนมัติในเวอร์ชั่นล่าสุด
vapcguy

คำตอบ:


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>

จากเอกสารประกอบ

พารามิเตอร์เพิ่มเติม

  • valueUpdate

    หากการโยงของคุณรวมถึงพารามิเตอร์ที่เรียกว่า valueUpdate สิ่งนี้จะกำหนดว่าเหตุการณ์เบราว์เซอร์ใด KO ควรใช้เพื่อตรวจจับการเปลี่ยนแปลง ค่าสตริงต่อไปนี้เป็นตัวเลือกที่มีประโยชน์มากที่สุด:

    • "เปลี่ยน" (ค่าเริ่มต้น) - อัปเดตโมเดลมุมมองของคุณเมื่อผู้ใช้ย้ายโฟกัสไปยังตัวควบคุมอื่นหรือในกรณีขององค์ประกอบทันทีหลังการเปลี่ยนแปลงใด ๆ

    • "keyup" - อัพเดตโมเดลมุมมองของคุณเมื่อผู้ใช้ปล่อยคีย์

    • "keypress" - อัพเดตโมเดลมุมมองของคุณเมื่อผู้ใช้พิมพ์คีย์ ต่างจากการกดคีย์การอัปเดตนี้ซ้ำ ๆ ในขณะที่ผู้ใช้กดคีย์ค้าง

    • "afterkeydown" - อัปเดตโมเดลมุมมองของคุณทันทีที่ผู้ใช้เริ่มพิมพ์อักขระ สิ่งนี้ทำงานได้โดยจับเหตุการณ์ keydown ของเบราว์เซอร์และจัดการเหตุการณ์แบบอะซิงโครนัส

ในตัวเลือกเหล่านี้ "afterkeydown" เป็นตัวเลือกที่ดีที่สุดหากคุณต้องการให้โมเดลการดูของคุณอัปเดตตามเวลาจริง


9
จาก docs ใน knockout.js: // ไวยากรณ์ "after <eventname>" หมายถึง "เรียกใช้ตัวจัดการแบบอะซิงโครนัสหลังเหตุการณ์" // สิ่งนี้มีประโยชน์ตัวอย่างเช่นเพื่อจับเหตุการณ์ "keydown" หลังจากเบราว์เซอร์ได้ปรับปรุงการควบคุม
John Wright

4
อย่างไรก็ตามมีการรับ valueUpdate: 'afterkeydown' เป็นค่าเริ่มต้นหรือไม่
Aaron Shafovaloff

2
สำหรับกล่องป้อนข้อมูลบางกล่องเบราว์เซอร์จะแสดงค่า "ป้อนอัตโนมัติ" (เช่นถ้าช่องป้อนข้อมูลมีชื่อว่า "ชื่อ") การเลือกจากตัวเติมอัตโนมัติไม่ทำงานกับ "afterkeydown" มีวิธีจับนี้ไหม
Anton

2
@Anton นอกเหนือจากการเติมค่าอัตโนมัติแล้วยังมีการคลิกแป้นพิมพ์บนหน้าจอและเหตุการณ์การวางเมาส์ที่ควรจับ การใช้afterkeydownเป็นทางออกที่ไม่ดี
John Kurlak

2
ผู้เขียนของคำตอบนี้โปรดปรับปรุงยังรวมถึงคำตอบของ Salvador Dali, textInput เพิ่มเป็น 3.2 เป็นทางออกที่ดีกว่าที่มีเข้ากันได้ดีกับเบราว์เซอร์บนมือถือ (สิ่งที่ต้องการโดยอัตโนมัติทำงานสมบูรณ์ดีกว่า)
ไมเคิลผู้กระทำความผิด

85

ในเวอร์ชัน 3.2คุณสามารถใช้การโยงข้อความเข้า :

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

มันทำสองสิ่งสำคัญ:

  • ทำการอัปเดตทันที
  • จัดการความแตกต่างของเบราว์เซอร์สำหรับตัด, ลาก, เติมข้อความอัตโนมัติ ...

ดังนั้นไม่จำเป็นต้องมีโมดูลเพิ่มเติมการควบคุมที่กำหนดเองและสิ่งอื่น ๆ


มันใช้งานได้ดีจริงๆและเป็นสิ่งที่ฉันต้องการเพื่อแทนที่ value: field, valueUpdate: 'input change' ที่ฉันมีผ่านแอพของฉัน ... :) ขอบคุณ
Tod Thomson

มีวิธีในการจับภาพเหตุการณ์หรือไม่เมื่อผู้ใช้คลิกที่ไอคอน 'x' ในช่องป้อนข้อมูลการค้นหา HTML5 ใหม่และทำหน้าที่เป็นกรณีที่อินพุตว่างเปล่า?
Codrina Valo

35

หากคุณต้องการให้อัปเดตafterkeydown"โดยค่าเริ่มต้น" คุณสามารถฉีดการvalueUpdateเชื่อมในvalueตัวจัดการการเชื่อม เพียงแค่จัดหาใหม่สำหรับการจัดการการใช้งานที่มีallBindingsAccessorafterkeydown

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

หากคุณไม่สะดวกในการ "แทนที่" การvalueเชื่อมโยงคุณสามารถตั้งชื่ออื่นให้กับชื่ออื่นและใช้ตัวจัดการการเชื่อมโยงนั้น

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

การสาธิต

วิธีแก้ปัญหาเช่นนี้เหมาะสำหรับการทำให้ล้มลงรุ่น 2.x ทีมสิ่งที่น่าพิศวงได้ทำการผูกมัดที่สมบูรณ์ยิ่งขึ้นสำหรับอินพุทแบบข้อความผ่านการโยงtextInputใน Knockout เวอร์ชัน 3 ขึ้นไป textareaมันถูกออกแบบมาเพื่อจัดการวิธีการป้อนข้อความทั้งหมดของปัจจัยการผลิตและข้อความ มันจะจัดการกับการอัพเดตตามเวลาจริงซึ่งทำให้วิธีการนี้ล้าสมัยอย่างมีประสิทธิภาพ


2
วิธีนี้ทำให้มาร์กอัปของฉันเป็นระเบียบมากขึ้น นอกจากนี้นอกเหนือจาก 'afterkeydown' แล้วคุณสามารถเพิ่ม 'อินพุท' และ 'วาง' เพื่อจัดการการวาง / ลากและวาง
บ๊อบ

ในการแก้ปัญหาข้างต้นฉันคิดว่า "typeof valueUpdated === 'array'" ต้องถูกแทนที่ด้วย "Object.prototype.toString.call (valueUpdate) === '[object Array]'" ดูstackoverflow.com/questions/4775722/…
daveywc

20

คำตอบของ Jeff Mercado นั้นยอดเยี่ยม แต่โชคไม่ดีที่มี Knockout 3

แต่ฉันพบคำตอบที่ ko devs แนะนำขณะทำงานผ่าน Knockout 3 การเปลี่ยนแปลง ดูความคิดเห็นด้านล่างที่https://github.com/knockout/knockout/pull/932 รหัสของพวกเขา:

//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/

แก้ไข Ko 3.2.0 ตอนนี้มีโซลูชันที่สมบูรณ์ยิ่งขึ้นด้วยการโยง "textInput" ใหม่ ดูคำตอบของ SalvidorDali


1
ขอบคุณที่อัพเดทคำตอบเป็น 3.0!
Graham T

@ GrahamT ใน KO 3.2 คุณไม่จำเป็นต้องใช้ มันเป็นเพียงหนึ่งบรรทัด
ซัลวาดอร์ดาลี

ดีมากสำหรับพวกเราใน KO 3.2 ที่ไม่รู้เกี่ยวกับ TextInput เมื่อเราเริ่มและไม่สามารถอัปเดตอินพุตทั้งหมดในระบบทั้งหมด!
cscott530
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.