AngularJS: การผูกแบบ ng-model ไม่อัปเดตเมื่อเปลี่ยนแปลงด้วย jQuery


100

นี่คือ HTML ของฉัน:

<input id="selectedDueDate" type="text" ng-model="selectedDate" />

เมื่อฉันพิมพ์ลงในช่องโมเดลจะได้รับการอัปเดตผ่านกลไกการผูก 2 ทาง หวาน.

อย่างไรก็ตามเมื่อฉันทำสิ่งนี้ผ่าน JQuery ...

$('#selectedDueDate').val(dateText);

มันไม่อัพเดตโมเดล ทำไม?


1
ทำไมคุณถึงทำอย่างที่สองเพื่อเริ่มต้นด้วย? คุณกำลังใช้เฟรมเวิร์กจากนั้นตัดสินใจที่จะข้ามและตั้งค่าผ่านการจัดการ DOM คำแนะนำที่ดีที่สุดที่สามารถให้กับผู้เริ่มต้นเชิงมุมได้: ลืม jquery อยู่ ใน 90% ของกรณีเชิงมุมจะเพียงพอและอีก 10% ที่เหลือสามารถทำได้ผ่าน jqlite ภายในลิงก์ของคำสั่ง (องค์ประกอบเป็นองค์ประกอบที่ห่อด้วย jqlite พร้อมที่จะจัดการ)
เป็นโมฆะ

1
คำถามที่สำคัญมาก
Syed Md. Kamruzzaman

มีเหตุผลที่ดีมากที่คุณอาจต้องการเปลี่ยนโมเดลเชิงมุมด้วยการจัดการ Dom บางทีคุณอาจเป็นนักพัฒนาที่ทำงานกับเครื่องมือทดสอบ A / B และต้องการกรอกแบบฟอร์มเบื้องหลังหรือคุณกำลังทำงานกับสคริปต์ greasemonkey เพื่อกรอกแบบฟอร์มอัตโนมัติ
Shadaez

คำตอบ:


135

Angular ไม่รู้เกี่ยวกับการเปลี่ยนแปลงนั้น สำหรับสิ่งนี้คุณควรโทร$scope.$digest()หรือทำการเปลี่ยนแปลงภายในของ$scope.$apply():

$scope.$apply(function() { 
   // every changes goes here
   $('#selectedDueDate').val(dateText); 
});

ดูสิ่งนี้เพื่อทำความเข้าใจการตรวจสอบความสกปรกให้ดีขึ้น

UPDATE : นี่คือตัวอย่าง


ฉันทำแบบนี้เหมือนที่คุณพูด: fiddle.jshell.net/AladdinMhaimeed/agvTz/8แต่ไม่ได้ผล
Aladdin Mhemed

1
ดูfiddle.jshell.net/agvTz/38นี้คุณควรเรียกfunction$ scope $ ใช้การส่งผ่านฟังก์ชันเป็นอาร์กิวเมนต์ และ $ apply ควรโทรเมื่อคุณจะทำการเปลี่ยนแปลงใน $ scope ดังนั้นภายใน onSelect อาฉันคาดว่าคุณใส่การจัดการ DOM ไว้ในตัวควบคุมเพียงเพื่อเป็นตัวอย่างในแอปจริงสิ่งนี้ผิด;)
Renan Tomal Fernandes

แล้วการฝึกเชิงมุมที่ดีจะทำอย่างไร? แยกการจัดการ DOM เป็นคำสั่ง?
Aladdin Mhemed

2
ใช่นี่คือตัวอย่างfiddle.jshell.net/agvTz/39คำสั่งสามารถใช้ได้หลายครั้งที่คุณต้องการด้วยdatepicker="scopeKeyThatYouWant"การป้อนข้อมูลง่ายๆ
Renan Tomal Fernandes

เพียงโทรไปที่ .. $ scope. $ Digest () จะช้าลงไหม
Thant Zin

29

เพียงใช้;

$('#selectedDueDate').val(dateText).trigger('input');

ฉันใช้trigger('input')กับ datepicker ในonSelectเหตุการณ์ มันอัปเดตค่าอย่างถูกต้อง
iman

นี้ได้เคล็ดลับสำหรับฉัน. ฉันกำลังอัปเดตค่าของอินพุตที่ถูกผูกไว้จากการทดสอบคำสั่งและการตัด.val('something'สายใน$apply(หรือการโทร$digestหลังจากนั้น) ไม่ได้ผล
Tom Seldon

2
หลังจากค้นหามาหลายชั่วโมงนี่คือสิ่งที่ได้ผล! ขอบคุณ!
แดน

Alhamdulillah สมบูรณ์แบบมันใช้ได้ผลสำหรับฉัน ขอบคุณที่ช่วยประหยัดเวลาของฉัน
Syed Md Kamruzzaman

จริง. ฉันใช้$('#selectedDueDate').val(dateText).trigger('change');สิ่งที่ไม่ได้ผลสำหรับฉัน .trigger('input');ใช้งานได้เหมือนเวทมนตร์
jafarbtech

17

ฉันพบว่าหากคุณไม่ใส่ตัวแปรตรงกับขอบเขตมันจะอัปเดตได้อย่างน่าเชื่อถือมากขึ้น

ลองใช้ "dateObj.selectedDate" และในตัวควบคุมเพิ่ม selectedDate ไปยังออบเจ็กต์ dateObj ดังนี้:

$scope.dateObj = {selectedDate: new Date()}

สิ่งนี้ได้ผลสำหรับฉัน


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

3
เหมือนกันที่นี่ - กูรู angularJs สามารถอธิบายได้หรือไม่ว่าเหตุใดจึงใช้งานได้ มันเหมือนกับว่ามุมมองนั้นมีขอบเขตซ้อนกันของตัวเองและบางครั้งคุณก็ติดขัดในการอัปเดตเพียงขอบเขตมุมมองไม่ใช่ขอบเขตตัวควบคุม
Tom Carver

1
ใช้ได้ดีกับฉัน! ฉันสงสัยว่าทำไมในห่ามันใช้ไม่ได้เหมือนกันในขอบเขตเปล่า
Stephen

1
มันมีส่วนเกี่ยวข้องเพียงเล็กน้อยกับเชิงมุมและเกี่ยวข้องกับการทำงานของจาวาสคริปต์ เมื่อคุณกำหนดตัวแปรขอบเขตให้กับออบเจ็กต์คุณจะกำหนดตัวแปรนั้นโดยการอ้างอิงซึ่งตรงข้ามกับค่าเมื่อกำหนดตัวแปรให้เท่ากับค่าดั้งเดิม ฉันได้พูดคุยเกี่ยวกับเรื่องนี้ในโพสต์ของฉันที่นี่ stackoverflow.com/questions/14527377/… . ผมอ้างอิงตีเสียงดังปังนี้ฉันทำในโพสต์ที่จะแสดงให้เห็นplnkr.co/edit/WkCT6aYao3qCmzJ8t5xg?p=preview
Nick Brady

4

ลองทำตามนี้

var selectedDueDateField = document.getElementById("selectedDueDate");
var element = angular.element(selectedDueDateField);
element.val('new value here');
element.triggerHandler('input');

สามารถใช้งานได้เมื่อคุณไม่มีสิทธิ์เข้าถึงขอบเขต $ ของตัวควบคุมเชิงมุม ตัวอย่างเช่นเมื่อคุณเขียนสคริปต์ด้วย Tampermonkey
wassertim


2

ไม่ว่าจะเกิดอะไรขึ้นนอกขอบเขตของ Angular Angular จะไม่มีทางรู้เลย

วงจรไดเจสต์ทำการเปลี่ยนแปลงจากโมเดล -> คอนโทรลเลอร์และจากคอนโทรลเลอร์ -> โมเดล

หากคุณต้องการดู Model ล่าสุดคุณต้องทริกเกอร์วงจรการย่อย

แต่มีโอกาสที่วงจรการย่อยกำลังดำเนินอยู่ดังนั้นเราจำเป็นต้องตรวจสอบและเริ่มต้นวงจร

ควรใช้อย่างปลอดภัยเสมอ

       $scope.safeApply = function(fn) {
            if (this.$root) {
                var phase = this.$root.$$phase;
                if (phase == '$apply' || phase == '$digest') {
                    if (fn && (typeof (fn) === 'function')) {
                        fn();
                    }
                } else {
                    this.$apply(fn);
                }
            }
        };


      $scope.safeApply(function(){
          // your function here.
      });

1

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

ในตัวควบคุม

app.module('yourModule').controller('yourController',function($scope){
$scope.vm={selectedDate:''}
});

ใน html

<div ng-controller="yourController">
<input id="selectedDueDate" type="text" ng-model="vm.selectedDate" />
</div>

1

คุณต้องทริกเกอร์เหตุการณ์การเปลี่ยนแปลงขององค์ประกอบอินพุตเนื่องจาก ng-model รับฟังเหตุการณ์อินพุตและขอบเขตจะได้รับการอัปเดต อย่างไรก็ตามทริกเกอร์ jQuery ปกติไม่ได้ผลสำหรับฉัน แต่นี่คือสิ่งที่ใช้งานได้เหมือนมีเสน่ห์

$("#myInput")[0].dispatchEvent(new Event("input", { bubbles: true })); //Works

การติดตามไม่ได้ผล

$("#myInput").trigger("change"); // Did't work for me

คุณสามารถอ่านเพิ่มเติมเกี่ยวกับการสร้างและการฝึกอบรมเหตุการณ์สังเคราะห์


0

ฉันได้เขียนปลั๊กอินเล็ก ๆ นี้สำหรับ jQuery ซึ่งจะทำการเรียกทั้งหมดเพื่อ.val(value)อัปเดตองค์ประกอบเชิงมุมหากมี:

(function($, ng) {
  'use strict';

  var $val = $.fn.val; // save original jQuery function

  // override jQuery function
  $.fn.val = function (value) {
    // if getter, just return original
    if (!arguments.length) {
      return $val.call(this);
    }

    // get result of original function
    var result = $val.call(this, value);

    // trigger angular input (this[0] is the DOM object)
    ng.element(this[0]).triggerHandler('input');

    // return the original result
    return result; 
  }
})(window.jQuery, window.angular);

เพียงแค่เปิดสคริปต์นี้หลังจาก jQuery และ angular.js และval(value)การอัปเดตควรเล่นได้ดี


เวอร์ชันย่อ:

!function(n,t){"use strict";var r=n.fn.val;n.fn.val=function(n){if(!arguments.length)return r.call(this);var e=r.call(this,n);return t.element(this[0]).triggerHandler("input"),e}}(window.jQuery,window.angular);

ตัวอย่าง:


คำตอบนี้ถูกคัดลอกคำต่อคำจากคำตอบของฉันคำถามอื่นที่คล้ายกัน


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