AngularJS: ng-model binding tidak diupdate saat diubah dengan jQuery


98

Ini HTML saya:

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

Saat saya mengetik ke dalam kotak, model diperbarui melalui mekanisme pengikatan 2 arah. Manis.

Namun ketika saya melakukan ini melalui JQuery ...

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

Itu tidak memperbarui model. Mengapa?


1
Mengapa Anda melakukan yang kedua untuk memulai? Anda menggunakan kerangka kerja dan kemudian memutuskan untuk melewatinya dan menyetel nilai melalui manipulasi DOM. Saran terbaik yang bisa diberikan dengan sudut pandang untuk pemula: lupakan jquery itu ada. dalam 90% kasus, sudut akan cukup dan 10% sisanya dapat dicapai melalui jqlite di dalam tautan direktif (elemen sebenarnya adalah elemen yang dibungkus jqlite yang siap untuk dimanipulasi).
Batal

1
pertanyaan yang sangat penting
Syed Md. Kamruzzaman

ada alasan yang sangat bagus mengapa Anda mungkin ingin mengubah model sudut dengan manipulasi dom, mungkin Anda seorang pengembang yang bekerja dengan alat pengujian A / B dan ingin mengisi formulir di belakang layar, atau Anda sedang mengerjakan skrip greasemonkey untuk mengisi formulir secara otomatis.
Shadaez

Jawaban:


134

Angular tidak tahu tentang perubahan itu. Untuk ini, Anda harus memanggil $scope.$digest()atau membuat perubahan di dalam $scope.$apply():

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

Lihat ini untuk lebih memahami pemeriksaan kotor

UPDATE : Berikut adalah contohnya


Saya membuat ini seperti yang Anda katakan: fiddle.jshell.net/AladdinMhaimeed/agvTz/8 tetapi tidak berhasil
Aladdin Mhemed

1
Lihat fiddle.jshell.net/agvTz/38 Anda harus memanggil function$ scope. $ Apply dengan meneruskan fungsi sebagai argumen. Dan $ apply harus dipanggil ketika Anda akan membuat perubahan pada $ scope, jadi, di dalam onSelect. Ah, saya berharap Anda meletakkan manipulasi DOM di dalam pengontrol hanya sebagai contoh, dalam aplikasi nyata ini salah;)
Renan Tomal Fernandes

lalu apa yang harus saya lakukan untuk membuat latihan sudut yang baik? pisahkan manipulasi DOM menjadi arahan?
Aladdin Mhemed

2
Ya, di sini contoh fiddle.jshell.net/agvTz/39 direktif dapat digunakan sebanyak yang Anda inginkan dengan datepicker="scopeKeyThatYouWant"masukan sederhana
Renan Tomal Fernandes

Cukup panggil .. $ scope. $ Digest () untuk menyelesaikan. akankah itu melambat?
Thant Zin

29

Gunakan saja;

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

Saya menggunakan trigger('input')datepicker dalam onSelectacara tersebut. Ini memperbarui nilai dengan benar.
iman

Ini melakukan trik untuk saya. Saya memperbarui nilai input terikat dari tes direktif dan membungkus .val('something'panggilan dalam $apply(atau menelepon $digestsesudahnya) tidak berfungsi.
Tom Seldon

2
Setelah berjam-jam mencari, inilah yang berhasil! Terima kasih!
Dan

Alhamdulillah berhasil untuk saya. terima kasih untuk menghemat waktu saya
Syed Md. Kamruzzaman

Benar. Saya menggunakan $('#selectedDueDate').val(dateText).trigger('change');yang tidak bekerja untuk saya. .trigger('input');bekerja seperti sulap
jafarbtech

17

Saya telah menemukan bahwa jika Anda tidak menempatkan variabel secara langsung terhadap ruang lingkup, itu akan diperbarui dengan lebih andal.

Coba gunakan beberapa "dateObj.selectedDate" dan di pengontrol tambahkan selectedDate ke objek dateObj sebagai berikut:

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

Ini berhasil untuk saya.


4
Ini berhasil juga untuk saya. Saya telah menghabiskan lebih dari 2 jam mencoba mencari tahu mengapa penjilidan dua arah tidak berhasil. Ini berfungsi dengan baik di halaman, tetapi cakupan di pengontrol tidak diperbarui. Kemudian saya mencoba pendekatan Anda karena putus asa (karena tidak masuk akal bagi saya bahwa ini harus benar) dan sial, itu berhasil! Terima kasih!
TMc

3
Sama di sini - dapatkah ada guru angularJs menjelaskan mengapa ini berhasil? Sepertinya tampilan memiliki cakupan bersarangnya sendiri dan terkadang Anda terjebak memperbarui hanya lingkup tampilan, bukan cakupan pengontrol
Tom Carver

1
Bekerja dengan baik untuk saya! Saya bertanya-tanya mengapa sih itu tidak berfungsi sama pada ruang lingkup kosong.
Stephen

1
Ini tidak ada hubungannya dengan angular, dan banyak hubungannya dengan cara kerja javascript. Saat Anda menetapkan variabel cakupan ke objek, Anda menetapkannya dengan referensi, bukan dengan nilai seperti yang dilakukan saat var disetel sama dengan nilai primitif. Saya membicarakannya di postingan saya di sini. stackoverflow.com/questions/14527377/… . Saya mereferensikan plunk ini yang saya buat di posting itu untuk menggambarkan plnkr.co/edit/WkCT6aYao3qCmzJ8t5xg?p=preview .
Nick Brady

4

Coba ini

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

Ini dapat digunakan ketika Anda tidak memiliki akses ke pengontrol sudut $ scope. Saat Anda menulis skrip dengan Tampermonkey, misalnya.
wassertim


2

Apapun yang terjadi di luar Scope of Angular, Angular tidak akan pernah tahu itu.

Siklus digest menempatkan perubahan dari model -> controller dan kemudian dari controller -> model.

Jika Anda perlu melihat Model terbaru, Anda perlu memicu siklus intisari

Tetapi ada kemungkinan siklus intisari sedang berlangsung, jadi kita perlu memeriksa dan memulai siklus tersebut.

Lebih disukai, selalu lakukan aplikasi yang aman.

       $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 melewatkan string, angka, dan boolean berdasarkan nilai saat ia melewati array dan objek dengan referensi. Jadi Anda bisa membuat objek kosong dan menjadikan tanggal Anda sebagai properti dari objek itu. Dengan cara itu angular akan mendeteksi perubahan model.

Dalam pengontrol

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

Dalam html

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

1

Anda harus memicu peristiwa perubahan elemen masukan karena ng-model mendengarkan peristiwa masukan dan cakupan akan diperbarui. Namun, pemicu jQuery biasa tidak berfungsi untuk saya. Tapi inilah yang berfungsi seperti pesona

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

Mengikuti tidak berhasil

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

Anda dapat membaca lebih lanjut tentang membuat dan mengirimkan peristiwa sintetis .


0

Saya telah menulis plugin kecil ini untuk jQuery yang akan membuat semua panggilan untuk .val(value)memperbarui elemen sudut jika ada:

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

Cukup masukkan skrip ini setelah jQuery dan angular.js dan val(value)pembaruan sekarang akan berfungsi dengan baik.


Versi yang diperkecil:

!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);

Contoh:


Jawaban ini disalin secara verbatim dari jawaban saya ke pertanyaan serupa lainnya .


0

Gunakan saja:

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

dari pada:

$('#selectedDueDate').val(dateText);
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.