AngularJS:jQueryで変更したときにng-modelバインディングが更新されない


98

これは私のHTMLです。

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

ボックスに入力すると、モデルは双方向バインディングメカニズムを介して更新されます。甘い。

しかし、JQueryを介してこれを行うと...

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

モデルは更新されません。どうして?


1
なぜ最初から2番目のものを行うのですか?フレームワークを使用していて、それをバイパスしてDOM操作を通じて値を設定することを決定しています。初心者に角度を付けて提供できる最善のアドバイス:jqueryが存在しないことを忘れます。90%の場合、角度は十分であり、残りの10%はディレクティブのリンク内のjqliteを介して達成できます(要素は実際にはjqliteでラップされた要素であり、操作する準備ができています)。
ボイド

1
非常に重要な質問
Syed Md。Kamruzzaman

dom操作で角度モデルを変更したいのには非常に良い理由があります。A/ Bテストツールを使用している開発者であり、舞台裏でフォームに記入したい場合、またはgreasemonkeyスクリプトで作業している場合などです。フォームに自動入力します。
Shadaez 2017

回答:


134

Angularはその変化を知りません。これについては、を呼び出す$scope.$digest()か、の内部で変更を行う必要があります$scope.$apply()

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

ダーティーチェックをよりよく理解するためにこれを見てください

更新ここに例があります


私はあなたが言うようにこれを作りました: fiddle.jshell.net/AladdinMhaimeed/agvTz/8しかし、それは機能しません
Aladdin Mhemed

1
このfiddle.jshell.net/agvTz/38を参照してくださいfunction。引数として関数を渡して$ scope。$ applyを呼び出す必要があります。また、$ select内で$ scopeを変更する場合は、$ applyを呼び出す必要があります。ああ、私はあなたが例のためだけにDOM操作をコントローラーの内部に置くことを期待しています、実際のアプリではこれは間違っています;)
Renan Tomal Fernandes

次に、良い角度の練習をするにはどうすればよいですか?DOM操作をディレクティブに分離しますか?
Aladdin Mhemed、2012年

2
はい、ここでは例fiddle.jshell.net/agvTz/39ディレクティブをシンプルなdatepicker="scopeKeyThatYouWant"入力で何度でも使用できます
Renan Tomal Fernandes 2012

ただ呼び出す.. $ scope。$ digest()で解決する。遅くなりますか?
Thant Zin

29

使用するだけです。

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

イベントtrigger('input')では日付ピッカーを使用しましたonSelect。値を正しく更新します。
イマーン2015年

これは私にとってはトリックでした。ディレクティブテストからバインドされた入力の値を更新していて、.val('something'呼び出しを$apply(または$digest後で呼び出す)でラップしても機能しませんでした。
トムセルドン2015

2
何時間も検索した結果、これが機能しました。ありがとうございました!
Dan

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、2014年

3
ここでも同じです-これが機能する理由をangularJsの第一人者が説明できますか?ビューには独自のネストされたスコープがあり、コントローラースコープではなく、ビュースコープだけを更新するのが難しい場合があります
Tom Carver

1
私にはうまくいきます!一体なぜそれが裸のスコープでは同じように機能しないのでしょうか?
スティーブン、

1
Angularとはほとんど関係がなく、JavaScriptがどのように機能するかと関係があります。スコープ変数をオブジェクトに割り当てるときは、varがプリミティブ値に設定されたときに行われるような値ではなく、参照によって割り当てます。私はここの私のポストでそれについて話しました。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');

角度のコントローラー$ scopeにアクセスできない場合に使用できます。たとえば、タンパーモンキーを使用してスクリプトを作成する場合。
wassertim


2

Angularの範囲外で何が起こっても、Angularはそれを知ることはありません。

ダイジェストサイクルは、モデル->コントローラー、次にコントローラー->モデルからの変更を反映します。

最新のモデルを表示する必要がある場合は、ダイジェストサイクルをトリガーする必要があります

ただし、ダイジェストサイクルが進行中の可能性があるため、サイクルを確認して初期化する必要があります。

できれば、常に安全な申請を行ってください。

       $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は文字列、数値、ブール値を値で渡し、配列とオブジェクトを参照で渡します。したがって、空のオブジェクトを作成して、日付をそのオブジェクトのプロパティにすることができます。このようにして、angularはモデルの変更を検出します。

コントローラ内

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

.val(value)存在する場合、角度要素を更新するためにすべての呼び出しを行うjQuery用のこの小さなプラグインを作成しました。

(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.