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?

Greg
sumber
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

Renan Tomal Fernandes
sumber
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');
Jan Kuri
sumber
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.

Ben Taliadoros
sumber
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');
sinar
sumber
Ini dapat digunakan ketika Anda tidak memiliki akses ke pengontrol sudut $ scope. Saat Anda menulis skrip dengan Tampermonkey, misalnya.
wassertim
3

Jalankan saja baris berikut di akhir fungsi Anda:

$ scope. $ apply ()

Rohan M Nabar
sumber
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.
      });
Rajendra kumar Vankadari
sumber
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>
Himanshu Mittal
sumber
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 .

Hari Das
sumber
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 .

dav_i
sumber
0

Gunakan saja:

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

dari pada:

$('#selectedDueDate').val(dateText);
Wekerle Tibor
sumber