Angularjs: input [text] ngChange เริ่มทำงานในขณะที่ค่ากำลังเปลี่ยนแปลง


92

ngChange กำลังเริ่มทำงานในขณะที่ค่ากำลังเปลี่ยนแปลง (ngChange ไม่เหมือนกับเหตุการณ์ onChange แบบคลาสสิก) ฉันจะผูกเหตุการณ์ onChange แบบคลาสสิกกับ angularjs ได้อย่างไรซึ่งจะเริ่มทำงานเมื่อมีการคอมมิตเนื้อหาเท่านั้น

ผลผูกพันปัจจุบัน:

<input type="text" ng-model="name" ng-change="update()" />

เพียงแค่มองหาสิ่งที่คล้ายกันและเกิดขึ้นกับฉันว่าคุณอาจต้องการพิจารณาอัปเดตเมื่อฟิลด์นั้นถูกต้องเท่านั้น ด้วยวิธีนี้ผู้ใช้สามารถต่อสู้กับการรับข้อมูลเข้าในรูปแบบที่ถูกต้อง (หรือคุณอาจช่วยพวกเขาในการแจ้งเตือนและตัวกรอง) จากนั้นคุณสามารถให้รางวัลแก่พวกเขาด้วยการอัปเดตเมื่อพวกเขาทำถูกต้อง!
Steve Black

วิธีการแก้ปัญหาที่มีความยืดหยุ่นมากขึ้นที่ช่วยให้การระบุเหตุการณ์ที่เกิดขึ้นกับการใช้งาน (ไม่เพียง แต่เบลอ) และคุณสมบัติอื่น ๆ ควรจะสร้างขึ้นในเร็ว ๆ นี้เชิงมุม: github.com/angular/angular.js/pull/2129
wired_in

คำตอบ:


96

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

นี่คือซอที่แสดงการเปลี่ยนแปลงของ ng-change ที่ทำงานร่วมกับคำสั่ง ng-model-on-เบลอใหม่ หมายเหตุ: นี่คือการปรับแต่งเล็กน้อยกับซอเดิม

หากคุณเพิ่มคำสั่งลงในรหัสของคุณคุณจะเปลี่ยนการเชื่อมโยงเป็นสิ่งนี้:

<input type="text" ng-model="name" ng-model-onblur ng-change="update()" />

นี่คือคำสั่ง:

// override the default input to update on blur
angular.module('app', []).directive('ngModelOnblur', function() {
    return {
        restrict: 'A',
        require: 'ngModel',
        priority: 1, // needed for angular 1.2.x
        link: function(scope, elm, attr, ngModelCtrl) {
            if (attr.type === 'radio' || attr.type === 'checkbox') return;

            elm.unbind('input').unbind('keydown').unbind('change');
            elm.bind('blur', function() {
                scope.$apply(function() {
                    ngModelCtrl.$setViewValue(elm.val());
                });         
            });
        }
    };
});

หมายเหตุ: เป็น @wjin กล่าวถึงในความคิดเห็นด้านล่างคุณลักษณะนี้ได้รับการสนับสนุนโดยตรงในเชิงมุม 1.3 (ปัจจุบันอยู่ในรุ่นเบต้า) ngModelOptionsผ่าน ดูเอกสารสำหรับข้อมูลเพิ่มเติม


1
ข้อควรระวัง elm.unbind ('input') พ่น 'TypeError' ใน Internet Explorer 8 ดังนั้นคำสั่ง unbind อื่น ๆ จะไม่ถูกดำเนินการเลย ฉันแก้ไขได้โดยย้าย elm.unbind ('input') ไปยังบรรทัดแยกต่างหากและล้อมรอบด้วยบล็อก try / catch
Rob Juurlink

1
Angular 1.2 มีng-blurคำสั่ง: docs.angularjs.org/api/ng.directive:ngBlur
JJ Zabkar

5
ฉันทำให้รหัสนี้ใช้งานได้ แต่ฉันต้องกำหนดลำดับความสำคัญของคำสั่ง (เช่นลำดับความสำคัญ: 100) ฉันใช้ Angular 1.2.10 ฉันเดาว่าคำสั่ง ngModelOnblur กำลังทำงานก่อนคำสั่ง ngModel ดังนั้นจึงยังไม่มีอะไรต้องเลิกผูก นอกจากนี้หน้านี้ยังทำให้ดูเหมือนว่าอาจมีโซลูชันในตัวสำหรับสิ่งนี้ในอนาคต: github.com/angular/angular.js/pull/1783
Alan West

4
หมายเหตุอย่างน้อยในเชิงมุม 1.3 ฟังก์ชันนี้ได้รับการสนับสนุนในการใช้งานเริ่มต้นผ่านทางng-model-options="{ updateOn: 'default blur' }"ดูเอกสาร
wjin

2
@RobJuurlink (หรือใครก็ตามที่พบ 'TypeError' ของ IE8 เมื่อพยายามผูกหรือเลิกผูกกับ 'อินพุต') - เมื่อดูที่แหล่งที่มาของ Angular คุณจะเห็นว่าพวกเขาใช้$snifferเพื่อตรวจสอบว่าเบราว์เซอร์รองรับ 'อินพุต' หรือไม่หากไม่เช่นนั้น พวกเขาถอยกลับไปที่ "คีย์ดาวน์" หากคุณอัปเดตคำสั่งข้างต้นเพื่อเลิกผูก 'อินพุต' เท่านั้นหาก$sniffer.hasEvent('input')ส่งกลับเป็นจริงคุณสามารถหลีกเลี่ยงข้อผิดพลาดนั้นและยังคงทำงานใน IE8 ได้
bvaughn

33

นี่เป็นข้อมูลเกี่ยวกับการเพิ่มล่าสุดของ AngularJS เพื่อใช้เป็นคำตอบในอนาคต (สำหรับคำถามอื่นด้วย )

Angular เวอร์ชันที่ใหม่กว่า (ตอนนี้อยู่ใน 1.3 เบต้า) AngularJS รองรับตัวเลือกนี้โดยใช้ngModelOptionsเช่น

ng-model-options="{ updateOn: 'default blur', debounce: { default: 500, blur: 0 } }"

เอกสาร NgModelOptions

ตัวอย่าง:

<input type="text" name="username"
       ng-model="user.name"
       ng-model-options="{updateOn: 'default blur', debounce: {default: 500, blur: 0} }" />

มันทำงานไม่ถูกต้องใน 1.3 เบต้า 5 แต่ได้รับการแก้ไขในรุ่นหลักปัจจุบัน 2602
manikanta

และนั่นคือสาเหตุที่มันยังอยู่ในรุ่นเบต้าและไม่สามารถใช้งานได้ในแอปพลิเคชัน "โลกแห่งความจริง" เช่นแอปพลิเคชันที่ฉันกำลังสร้างอยู่ในขณะนี้
reaper_unique

นี่คือตัวเลือก ng-model เช่นโมดูลสำหรับ Angular 1.2.x github.com/fergaldoyle/modelOptions
Fergal

8

ในกรณีที่ใครก็ตามที่กำลังมองหาการสนับสนุนการกดแป้น "enter" เพิ่มเติมนี่คือการอัปเดตของซอที่มีให้โดยGloppy

รหัสสำหรับการกดแป้นพิมพ์:

elm.bind("keydown keypress", function(event) {
    if (event.which === 13) {
        scope.$apply(function() {
            ngModelCtrl.$setViewValue(elm.val());
        });
    }
});

5

สำหรับใครก็ตามที่กำลังดิ้นรนกับ IE8 (ไม่ชอบการเลิกผูก ('อินพุต') ฉันพบวิธีแก้ไข

ฉีด $ sniffer ลงในคำสั่งของคุณและใช้:

if($sniffer.hasEvent('input')){
    elm.unbind('input');
}

IE8 สงบลงถ้าคุณทำสิ่งนี้ :)


หรือใช้ try / catch
สาย _ ใน

4

ตามความรู้ของฉันเราควรใช้ ng-change กับตัวเลือกเลือกและในกล่องข้อความเราควรใช้ ng-เบลอ


นี่เป็นคำตอบที่ถูกต้องในตอนนี้ย้อนกลับไปเมื่อคำถามถูกถามว่าไม่มีอยู่จริง
ลง

ขอบคุณมาก ... นี่น่าจะเป็นคำตอบ
Renjith

3

ไม่ได้ใช้ $ scope $ watch เพื่อสะท้อนการเปลี่ยนแปลงของตัวแปรขอบเขตดีกว่าหรือ?


1
อาหารสำหรับความคิด: benlesh.com/2013/10/title.html (หัวข้อ: คุณอาจไม่ควรใช้ $ watch ในคอนโทรลเลอร์ของคุณ)
BenB

0

แทนที่อินพุตเริ่มต้น onChange behavior (เรียกใช้ฟังก์ชันเฉพาะเมื่อโฟกัสการสูญเสียการควบคุมและค่าเปลี่ยนแปลง)

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

@param {String} - ชื่อฟังก์ชันที่จะเรียกใช้เมื่อ "onChange" ควรเริ่มทำงาน

@example <input my-on-change = "myFunc" ng-model = "model">

angular.module('app', []).directive('myOnChange', function () { 
    return {
        restrict: 'A',
        require: 'ngModel',
        scope: {
            myOnChange: '='
        },
        link: function (scope, elm, attr) {
            if (attr.type === 'radio' || attr.type === 'checkbox') {
                return;
            }
            // store value when get focus
            elm.bind('focus', function () {
                scope.value = elm.val();

            });

            // execute the event when loose focus and value was change
            elm.bind('blur', function () {
                var currentValue = elm.val();
                if (scope.value !== currentValue) {
                    if (scope.myOnChange) {
                        scope.myOnChange();
                    }
                }
            });
        }
    };
});

0

ฉันมีปัญหาเดียวกันทุกประการและสิ่งนี้ใช้ได้ผลสำหรับฉัน เพิ่มng-model-updateและng-keyupคุณพร้อมที่จะไป! นี่คือเอกสาร

 <input type="text" name="userName"
         ng-model="user.name"
         ng-change="update()"
         ng-model-options="{ updateOn: 'blur' }"
         ng-keyup="cancel($event)" />
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.