AngularJS: ng modeli bağlama, jQuery ile değiştirildiğinde güncellenmiyor


98

Bu benim HTML’im:

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

Kutuya yazdığımda model 2 yollu bağlama mekanizması ile güncelleniyor. Tatlı.

Ancak bunu JQuery aracılığıyla yaptığımda ...

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

Modeli güncellemez. Neden?


1
Başlamak için neden ikinciyi yaptın? Bir çerçeve kullanıyorsunuz ve ardından onu atlamaya ve DOM manipülasyonu yoluyla değeri ayarlamaya karar veriyorsunuz. Yeni başlayanlara açısal olarak verilebilecek en iyi tavsiye: jquery'nin var olduğunu unutun. durumların% 90'ında açısal yeterli olacaktır ve kalan% 10, bir direktifin bağlantısı içindeki jqlite aracılığıyla elde edilebilir (öğe aslında manipüle edilmeye hazır bir jqlite sarılı öğedir).
Void

1
çok önemli soru
Syed Md. Kamruzzaman

dom manipülasyonu ile açısal modelleri değiştirmek isteyebileceğiniz çok iyi nedenler var, belki bir A / B test aracıyla çalışan bir geliştiricisiniz ve perde arkasındaki formları doldurmak istiyorsunuz veya bir greasemonkey betiği üzerinde çalışıyorsunuz formları otomatik doldurmak için.
Shadaez

Yanıtlar:


134

Angular bu değişikliği bilmiyor. Bunun için şunları aramalı $scope.$digest()veya içinde değişiklik yapmalısınız $scope.$apply():

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

Bkz bu daha iyi anlamak için kirli denetimine

GÜNCELLEME : İşte bir örnek


Bunu senin dediğin gibi yaptım: fiddle.jshell.net/AladdinMhaimeed/agvTz/8 ama işe yaramıyor
Aladdin Mhemed

1
Bakınız fiddle.jshell.net/agvTz/38function $ kapsamı çağırmalısınız . $ Apply bir işlevi bağımsız değişken olarak geçirirken . Ayrıca, değişiklikleri $ kapsamda yapacağınız zaman $ apply çağrılmalıdır, yani onSelect'in içinde. Ah, sadece örnek için DOM manipülasyonunu denetleyicinin içine koymanızı bekliyorum, gerçek bir uygulamada bu yanlış;)
Renan Tomal Fernandes

o zaman iyi bir açısal uygulama yapmak için ne yapmalıyım? DOM manipülasyonunu bir yönergeye ayırmak?
Aladdin Mhemed

2
Evet, işte bir örnek fiddle.jshell.net/agvTz/39 yönergesi bir basit ile istediğiniz birçok kez olarak kullanılabilir datepicker="scopeKeyThatYouWant"girişteki
Renan Tomal Fernandes

Yerleşmek için .. $ kapsam. yavaşlayacak mı?
Thant Zin

29

Sadece kullan;

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

Etkinliğinde trigger('input')bir tarih seçici ile kullandım onSelect. Değeri doğru şekilde günceller.
iman

Bu benim için hile yaptı. Bir yönerge testinden bağlı bir girdinin değerini güncelliyordum ve .val('something'aramayı bir $apply(veya $digestdaha sonra arama ) içine almak işe yaramadı.
Tom Seldon

2
Saatler süren aramadan sonra, işe yarayan buydu! Teşekkür ederim!
Dan

Elhamdulillah, mükemmel, benim için çalışıyor. saatlerimi kurtardığın için teşekkürler
Syed Md. Kamruzzaman

Doğru. Benim $('#selectedDueDate').val(dateText).trigger('change');için çalışmayan kullanıyordum . .trigger('input');sihir gibi çalışır
jafarbtech

17

Değişkeni doğrudan kapsamın karşısına koymazsanız daha güvenilir bir şekilde güncellendiğini buldum.

Bazı "dateObj.selectedDate" kullanmayı deneyin ve denetleyicide selectedDate'i bir dateObj nesnesine şu şekilde ekleyin:

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

Bu benim için çalıştı.


4
Bu benim için de çalıştı. İki yönlü bağlamanın neden işe yaramadığını anlamaya çalışırken 2 saatten fazla zaman harcadım. Sayfada iyi çalıştı, ancak denetleyicideki kapsam güncellenmiyordu. Sonra yaklaşımınızı umutsuzluktan denedim (çünkü bunun doğru olması bana mantıklı gelmiyordu) ve lanet olsun, işe yaradı! Teşekkürler!
TMc

3
Burada da aynı - herhangi bir angularJs gurusu bunun neden işe yaradığını açıklayabilir mi? Görünümü kendi iç içe kapsam var sahiptir ve bazen takılıp güncellemesi yalnızca görüntüleme kapsamını değil, kontrolör-kapsamını olsun Sanki
Tom Carver

1
Benim için iyi çalışıyor! Acaba neden çıplak kapsamda aynı şekilde çalışmıyor?
Stephen

1
Bunun açısal ile çok az ilgisi vardır ve javascript'in nasıl çalıştığı ile çok ilgisi vardır. Kapsam değişkenini bir nesneye atadığınızda, bir var ilkel bir değere eşit olarak ayarlandığında yapılan değerin aksine, bunu referansa göre atarsınız. Buradaki yazımda bunun hakkında konuştum. stackoverflow.com/questions/14527377/… . Bu yazıda plnkr.co/edit/WkCT6aYao3qCmzJ8t5xg?p=preview göstermek için bu yazıyı referans aldım .
Nick Brady

4

Bunu dene

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

Açısal denetleyicinin $ kapsamına erişiminiz olmadığında kullanılabilir. Örneğin Tampermonkey ile bir betik yazdığınızda.
wassertim

3

Fonksiyonunuzun sonunda aşağıdaki satırı çalıştırın:

$ kapsam. $ uygula ()


2

Angular'ın Kapsamı dışında ne olursa olsun, Angular bunu asla bilemez.

Özet döngüsü, modelden -> denetleyiciden ve sonra denetleyiciden -> modelden değişiklikleri koyar.

En son Modeli görmeniz gerekiyorsa, özet döngüsünü tetiklemeniz gerekir

Ancak devam eden bir sindirim döngüsü şansı var, bu yüzden döngüyü kontrol etmemiz ve başlatmamız gerekiyor.

Tercihen her zaman güvenli bir başvuru yapın.

       $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 dizileri ve nesneleri başvuruya göre geçirirken dize, sayılar ve mantıksal değerleri değere göre geçirir. Böylece boş bir nesne oluşturabilir ve tarihinizi bu nesnenin bir özelliği yapabilirsiniz. Bu şekilde açısal, model değişikliklerini algılayacaktır.

Denetleyicide

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

Html olarak

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

1

Giriş öğesinin değişim olayını tetiklemelisiniz çünkü ng-modeli giriş olaylarını dinler ve kapsam güncellenir. Ancak, normal jQuery tetikleyicisi benim için çalışmadı . Ama işte bir cazibe gibi çalışan şey

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

Takip işe yaramadı

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

Sentetik olaylar oluşturma ve gönderme hakkında daha fazla bilgi edinebilirsiniz .


0

JQuery için bu küçük eklentiyi yazdım .val(value), eğer mevcutsa açısal öğeyi güncellemek için tüm çağrıları yapacak :

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

Sadece jQuery ve angular.js'den sonra bu komut dosyasını açın ve val(value)güncellemeler artık iyi oynamalıdır.


Küçültülmüş sürüm:

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

Misal:


Bu cevap, cevabımdan aynen başka bir benzer soruya kopyalandı .


0

Sadece kullan:

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

onun yerine:

$('#selectedDueDate').val(dateText);
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.