web-dev-qa-db-fra.com

Mettre à jour le modèle Angular après avoir défini la valeur d'entrée avec jQuery

J'ai ce scénario simple:

Elément d'entrée dont la valeur est modifiée par la méthode val () de jQuery.

J'essaie de mettre à jour le modèle angular avec la valeur définie par jQuery. J'ai essayé d'écrire une directive simple, mais elle ne fait pas ce que je veux.

Voici la directive:

var myApp = angular.module('myApp', []);
myApp.directive('testChange', function() {
    return function(scope, element, attrs) {        
        element.bind('change', function() {
            console.log('value changed');
        })
    }
})

c'est la partie jQuery:

$(function(){
    $('button').click(function(){
        $('input').val('xxx');
    })
})

et html:

<div ng-app="myApp">
    <div ng-controller="MyCtrl">
        <input test-change ng-model="foo" />
        <span>{{foo}}</span>
    </div>
</div>

<button>clickme</button>

Voici le violon de mon essai:
http://jsfiddle.net/U3pVM/743/

Est-ce que quelqu'un peut me diriger dans la bonne direction?

155
Michal J.

ngModel écoute l'événement "input". Pour "réparer" votre code, vous devez donc déclencher cet événement après avoir défini la valeur:

$('button').click(function(){
    var input = $('input');
    input.val('xxx');
    input.trigger('input'); // Use for Chrome/Firefox/Edge
    input.trigger('change'); // Use for Chrome/Firefox/Edge + IE11
});

Pour l'explication de ce comportement particulier, consultez la réponse que j'ai donnée il y a quelque temps: " Comment AngularJS intercepte-t-il en interne des événements tels que 'onclick', 'onchange'? "


Mais malheureusement, ce n'est pas le seul problème que vous avez. Comme indiqué dans d'autres commentaires de publication, votre approche centrée sur jQuery est tout à fait fausse. Pour plus d’informations, jetez un oeil à cet article: Comment puis-je "penser à AngularJS" si j’ai un fond jQuery? ).

317
Stewie

J'espère que cela est utile pour quelqu'un.

Je ne pouvais pas récupérer l'événement jQuery('#myInputElement').trigger('input') à mon application angular.

J'étais cependant capable de récupérer angular.element(jQuery('#myInputElement')).triggerHandler('input').

58
ginman

Je ne pense pas que jQuery est nécessaire ici.

Vous pouvez utiliser $ watch et ng-click à la place

<div ng-app="myApp">
  <div ng-controller="MyCtrl">
    <input test-change ng-model="foo" />
    <span>{{foo}}</span>

    <button ng-click=" foo= 'xxx' ">click me</button>
    <!-- this changes foo value, you can also call a function from your controller -->
  </div>
</div>

Dans votre contrôleur:

$scope.$watch('foo', function(newValue, oldValue) {
  console.log(newValue);
  console.log(oldValue);
});
22
Utopik

Vous devez utiliser le code suivant pour mettre à jour la portée du modèle d'entrée spécifique comme suit

$('button').on('click', function(){
    var newVal = $(this).data('val');
    $('select').val(newVal).change();

    var scope = angular.element($("select")).scope();
    scope.$apply(function(){
        scope.selectValue = newVal;
    });
});
17
jayM

La réponse acceptée qui déclenchait l'événement input avec jQuery ne fonctionnait pas pour moi. La création d'un événement et l'envoi avec JavaScript natif ont fait l'affaire.

$("input")[0].dispatchEvent(new Event("input", { bubbles: true }));
16
Martins Balodis

J'ai apporté des modifications à l'initialisation du contrôleur uniquement en ajoutant le programme d'écoute sur le bouton d'action:

$(document).on('click', '#action-button', function () {
        $timeout(function () {
             angular.element($('#input')).triggerHandler('input');
        });
});

D'autres solutions n'ont pas fonctionné dans mon cas.

7
Ebru Yener

Je sais qu'il est un peu tard pour répondre ici, mais je pourrais peut-être économiser du temps.

J'ai eu le même problème. Un modèle ne sera pas peuplé une fois que vous aurez mis à jour la valeur de l'entrée de jQuery. J'ai essayé d'utiliser des événements déclencheurs mais aucun résultat.

Voici ce que j'ai fait qui pourrait vous sauver la journée.

Déclarez une variable au sein de votre balise de script en HTML.

Comme:

<script>
 var inputValue="";

// update that variable using your jQuery function with appropriate value, you want...

</script>

Une fois que vous avez fait cela en utilisant le service ci-dessous de angular.

fenêtre $

Maintenant, ci-dessous, la fonction getData appelée à partir du même périmètre de contrôleur vous donnera la valeur souhaitée.

var myApp = angular.module('myApp', []);

app.controller('imageManagerCtrl',['$scope','$window',function($scope,$window) {

$scope.getData = function () {
    console.log("Window value " + $window.inputValue);
}}]);
3
Khawaja Asim

Si vous utilisez IE, vous devez utiliser: input.trigger ("change");

2
William

ajoutez .change() après avoir réglé la valeur.

exemple: ('id').val.('value').change();

n'oubliez pas d'ajouter la balise onchange ou ng-change au format HTML.

2
Azeez

J'ai écrit ce petit plugin pour jQuery qui fera tous les appels à .val(value) mettre à jour l'élément angular 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>
2
dav_i

J'ai fait cela pour pouvoir mettre à jour la valeur de ngModel de l'extérieur avec Vanilla/jQuery:

function getScope(fieldElement) {
    var $scope = angular.element(fieldElement).scope();
    var nameScope;
    var name = fieldElement.getAttribute('name');
    if($scope) {
        if($scope.form) {
            nameScope = $scope.form[name];
        } else if($scope[name]) {
            nameScope = $scope[name];
        }
    }
    return nameScope;
}

function setScopeValue(fieldElement, newValue) {
    var $scope = getScope(fieldElement);
    if($scope) {
        $scope.$setViewValue(newValue);
        $scope.$validate();
        $scope.$render();
    }
}

setScopeValue(document.getElementById("fieldId"), "new value");
0
anlijudavid