163 votes

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

J'ai ce simple scénario :

Élé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 angulaire avec la valeur que jQuery a défini. 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 avec mon essai :
http://jsfiddle.net/U3pVM/743/

Quelqu'un peut-il m'indiquer la bonne direction ?

2 votes

Mélanger AngularJS et jQuery, en dehors des directives, est souvent une mauvaise idée. Est-ce que jQuery est obligatoire pour ce que vous voulez faire ?

0 votes

Pourquoi ne pas définir l'événement de clic avec angular à une fonction dans le contrôleur pour changer la valeur du modèle ?

0 votes

@Blackhole, j'utilise le plugin jquery upload qui fait son travail et met le chemin du fichier téléchargé dans l'entrée cachée. Tout ce dont j'ai besoin est d'avoir accès à ce chemin dans le modèle angulaire. Je me suis donc dit que j'allais le définir comme une valeur de l'entrée cachée et après qu'il ait été modifié, mettre à jour le modèle angulaire.

329voto

Stewie Points 20312

NgModel écoute l'événement "input", donc pour "corriger" votre code, vous devez 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 cette réponse que j'ai donnée il y a quelque temps : " Comment AngularJS capte-t-il en interne des événements tels que "onclick" ou "onchange" ? "


Mais malheureusement, ce n'est pas le seul problème que vous rencontrez. Comme indiqué dans d'autres commentaires, votre approche centrée sur JQuery est tout simplement erronée. Pour plus d'informations, consultez cet article : Comment puis-je "penser en AngularJS" si j'ai une formation en jQuery ? ).

5 votes

Cool ! À une exception près : pourquoi cela ne fonctionne-t-il pas sur les entrées cachées ? Lorsque je change mon type d'entrée en texte, cela fonctionne comme prévu.

8 votes

Cela a résolu un problème majeur lors de l'utilisation des plugins de calendrier jquery. En modifiant le plugin pour déclencher('input') après input.val(), l'événement ng-change se déclenche après que l'utilisateur ait sélectionné la date du calendrier. Merci !

3 votes

Fonctionne parfaitement sur une entrée cachée : element.triggerHandler("change") ;

61voto

ginman Points 513

J'espère que cela sera utile à quelqu'un.

Je n'ai pas réussi à obtenir le jQuery('#myInputElement').trigger('input') pour être récupéré par mon application angulaire.

J'ai cependant réussi à obtenir angular.element(jQuery('#myInputElement')).triggerHandler('input') pour être ramassé.

2 votes

S'il vous plaît expliquer la solution dont juste écrire le code. je reçois angular n'est pas $ n'est pas une fonction

1 votes

$ représente jQuery ici. Il est marqué dans la question.

0 votes

Cela a également fonctionné pour moi, alors que $('myInputElement').trigger('input') n'était pas fiable. Il semblait fonctionner de manière aléatoire, parfois mais pas toujours, et je n'ai jamais pu établir un modèle. Cette solution fonctionne à chaque fois.

28voto

Martins Balodis Points 509

La réponse acceptée qui déclenchait input avec jQuery n'a pas fonctionné pour moi. La création d'un événement et sa répartition avec le JavaScript natif ont fait l'affaire.

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

22voto

Utopik Points 1323

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

Vous pouvez utiliser Montre y ng-click au lieu de

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

1 votes

Merci Utopik, vous avez raison, je ne devrais pas mélanger jquery avec angular quand il y a un moyen de faire le travail en utilisant angular.

18voto

jayM Points 251

Vous devez utiliser le code suivant afin de 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;
    });
});

1 votes

var scope = angular.element($("select")).scope(); scope.$apply(function(){ scope.selectValue = newVal; }); cette partie m'a beaucoup aidé. Mon problème était de mettre à jour un modèle angulaire après un appel jquery ajax dans la fonction de succès. C'était lent avec $http parce qu'il y avait un écouteur d'événement de changement en double pour l'élément qui faisait autre chose, donc je l'ai fusionné dans jQuery.

1 votes

L'utilisation de element.scope() est une mauvaise idée, car elle ne fonctionne que si la journalisation est activée. Si vous êtes sur un site de production, vous devez désactiver la journalisation dans votre configuration avec la commande $compileProvider.debugInfoEnabled(false); o $logProvider.debugEnabled(false); Voir code.angularjs.org/1.4.0/docs/guide/production pour plus d'informations.

0 votes

J'ai essayé cette méthode pour une variable cachée et cela a fonctionné. var li_cuboid_id = $('#li_cuboid_id') ; li_cuboid_id.val(json.cuboidId).change() ; var scope = angular.element($("#li_cuboid_id")).scope() ; scope.$apply(function(){ scope.cuboidId = json.cuboidId ; }) ; la variable cachée est définie comme : <input id="li_cuboid_id" type=hidden ng-model="cuboidId">

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X