web-dev-qa-db-fra.com

AngularJS: la liaison ng-model n'est pas mise à jour lorsqu'elle est modifiée avec jQuery

C'est mon HTML:

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

Lorsque je tape dans la zone, le modèle est mis à jour via le mécanisme de liaison bidirectionnelle. Sucré.

Cependant quand je fais cela via JQuery ...

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

Il ne met pas à jour le modèle. Pourquoi?

97
Greg

Angular ne sait pas ce changement. Pour cela, vous devez appeler $scope.$digest() ou effectuer le changement à l'intérieur de $scope.$apply():

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

Voir ceci pour mieux comprendre sale vérification _

UPDATE: Here est un exemple

131

Juste utiliser; 

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

J'ai constaté que si vous ne comparez pas directement la variable à l'étendue, elle se met à jour de manière plus fiable.

Essayez d’utiliser "dateObj.selectedDate" et dans le contrôleur, ajoutez la selectedDate à un objet dateObj comme suit:

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

Cela a fonctionné pour moi.

16
Ben Taliadoros

Essaye ça

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

Il suffit de lancer la ligne suivante à la fin de votre fonction: 

$ scope. $ apply () 

2
Rohan M Nabar

Quoi qu’il se passe en dehors du champ d’application d’Angle, Angular ne le saura jamais. 

Le cycle de synthèse résume les modifications du modèle -> contrôleur puis du contrôleur -> modèle. 

Si vous avez besoin de voir le dernier modèle, vous devez déclencher le cycle de synthèse. 

Mais il y a une chance qu'un cycle de digestion soit en cours, nous devons donc vérifier et lancer le cycle.

De préférence, effectuez toujours une application en toute sécurité.

       $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.
      });
2

Vous devez déclencher l'événement change de l'élément input car ng-model écoute les événements input et la portée sera mise à jour. Cependant, le déclencheur jQuery regular n'a pas fonctionné pour moi. Mais voici ce qui fonctionne comme un charme

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

Suivre n'a pas fonctionné

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

Vous pouvez en savoir plus sur la création et la distribution d’événements synthétiques .

1
Hari Das

AngularJS transmet chaîne, nombres et booléens par valeur, tandis qu'il passe tableaux et objets par référence Vous pouvez donc créer un objet vide et faire de votre date une propriété de cet objet. De cette façon, angular détectera les changements de modèle.

Dans le contrôleur

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

En html

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

Il suffit d'utiliser:

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

au lieu de:

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

J'ai écrit ce petit plugin pour jQuery qui fera tous les appels à .val(value) mettre à jour l'élément angulaire s'il est présent:

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

Il suffit d’ajouter ce script après les mises à jour jQuery et angular.js et val(value) devrait maintenant jouer à Nice.


Version minifiée:

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

Exemple:

// the function
(function($, ng) {
  'use strict';
  
  var $val = $.fn.val;
  
  $.fn.val = function (value) {
    if (!arguments.length) {
      return $val.call(this);
    }
    
    var result = $val.call(this, value);
    
    ng.element(this[0]).triggerHandler('input');
    
    return result;
    
  }
})(window.jQuery, window.angular);

(function(ng){ 
  ng.module('example', [])
    .controller('ExampleController', function($scope) {
      $scope.output = "output";
      
      $scope.change = function() {
        $scope.output = "" + $scope.input;
      }
    });
})(window.angular);

(function($){  
  $(function() {
    var button = $('#button');
  
    if (button.length)
      console.log('hello, button');
    
    button.click(function() {
      var input = $('#input');
      
      var value = parseInt(input.val());
      value = isNaN(value) ? 0 : value;
      
      input.val(value + 1);
    });
  });
})(window.jQuery);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div ng-app="example" ng-controller="ExampleController">
  <input type="number" id="input" ng-model="input" ng-change="change()" />
  <span>{{output}}</span>
  <button id="button">+</button>
</div>


Cette réponse a été copiée textuellement de ma réponse à une autre question similaire .

0
dav_i