Cliquer sur une case à cocher avec ng-click ne met pas à jour le modèle


85

En cliquant sur une case à cocher et en appelant ng-click: le modèle n'est pas mis à jour avant que ng-click ne démarre, donc la valeur de la case à cocher est mal présentée dans l'interface utilisateur:

Cela fonctionne dans AngularJS 1.0.7 et semble cassé dans Angualar 1.2-RCx.

<div ng-app="myApp" ng-controller="Ctrl">
<li  ng-repeat="todo in todos">
  <input type='checkbox' ng-click='onCompleteTodo(todo)' ng-model="todo.done">
    {{todo.text}}
</li> 
<hr>
task: {{todoText}}
<hr><h2>Wrong value</h2>
     done: {{doneAfterClick}}

et contrôleur:

angular.module('myApp', [])
  .controller('Ctrl', ['$scope', function($scope) {
    $scope.todos=[
        {'text': "get milk",
         'done': true
         },
        {'text': "get milk2",
         'done': false
         }
        ];


   $scope.onCompleteTodo = function(todo) {
    console.log("onCompleteTodo -done: " + todo.done + " : " + todo.text);
    $scope.doneAfterClick=todo.done;
    $scope.todoText = todo.text;

   };
}]);

Violon cassé avec Angular 1.2 RCx - http://jsfiddle.net/supercobra/ekD3r/

Fidddle de travail avec Angular 1.0.0 - http://jsfiddle.net/supercobra/8FQNw/


3
Également cassé pour moi maintenant que j'ai mis à jour Angular vers 1.2+
ac360

Également cassé dans la v1.2.24.
Vincent P

Réponses:


165

Que diriez-vous de changer

<input type='checkbox' ng-click='onCompleteTodo(todo)' ng-model="todo.done">

à

<input type='checkbox' ng-change='onCompleteTodo(todo)' ng-model="todo.done">

À partir de la documentation :

Évaluez l'expression donnée lorsque l'utilisateur modifie l'entrée. L'expression n'est pas évaluée lorsque le changement de valeur provient du modèle.

Notez que cette directive doit ngModelêtre présente.


3
cela semble également être cassé dans la version 1.2.7
JvdBerg

Ampoule sacrée, Batman! Je pensais que je faisais quelque chose de complètement faux, mais cela s'est avéré aussi simple que cela.
Adam Marshall

1
Réponse très utile! +1 Angular doc -1
neurix

Que faire si vous avez besoin des données d'événement pour empêcher Par défaut?
user1943442


9

L'ordre dans lequel ng-clicket ng-modelsera exécuté est ambigu (puisque ni l'un ni l'autre ne les définissent explicitement priority). La solution la plus stable à cela serait d'éviter de les utiliser sur le même élément.

En outre, vous ne voulez probablement pas du comportement que les exemples montrent; vous voulez que le checkboxréponde aux clics sur le texte complet de l' étiquette , pas seulement sur la case à cocher. Par conséquent, la solution la plus propre serait d'envelopper le input(avec ng-model) dans un label(avec ng-click):

<label ng-click="onCompleteTodo(todo)">
  <input type='checkbox' ng-model="todo.done">
  {{todo.text}}
</label>

Exemple de travail: http://jsfiddle.net/b3NLH/1/


Merci beaucoup! C'est la seule solution qui a fonctionné pour moi!
DaniCE

Cette solution est toujours la meilleure!
Ellisan

8

Pourquoi n'utilisez-vous pas

$watch('todo',function(.....

Ou une autre solution serait de définir l' todo.doneintérieur du rappel ng-click et d'utiliser uniquement ng-click

<div ng-app="myApp" ng-controller="Ctrl">
<li  ng-repeat="todo in todos">
<input type='checkbox' ng-click='onCompleteTodo(todo)'>
    {{todo.text}} {{todo.done}}

et

$scope.onCompleteTodo = function(todo) {
        todo.done = !todo.done; //toggle value
        console.log("onCompleteTodo -done: " + todo.done + " : " + todo.text);
        $scope.current = todo;
}

2
Voir la réponse @kakoni, j'ai utilisé ng-change au lieu de ng-click et le timing fonctionne très bien. Cela vous permet de conserver la liaison bidirectionnelle et constitue une approche beaucoup plus propre.
Michael Moser

6

Remplacer ng-model par ng-checked fonctionne pour moi.


Juste ce que je voulais. Merci!
Isaac le

Je viens de travailler pour moi à partir de toutes les solutions disponibles ici.
thatzprem

2

C'est une sorte de hack mais l'envelopper dans un délai d'attente semble accomplir ce que vous recherchez:

angular.module('myApp', [])
    .controller('Ctrl', ['$scope', '$timeout', function ($scope, $timeout) {
    $scope.todos = [{
        'text': "get milk",
        'done': true
    }, {
        'text': "get milk2",
            'done': false
    }];

    $scope.onCompleteTodo = function (todo) {
        $timeout(function(){
            console.log("onCompleteTodo -done: " + todo.done + " : " + todo.text);
            $scope.doneAfterClick = todo.done;
            $scope.todoText = todo.text;
        });
    };
}]);

1

L'ordre entre ng-modelet ng-clicksemble être différent et c'est quelque chose sur lequel vous ne devriez probablement pas vous fier. Au lieu de cela, vous pouvez faire quelque chose comme ceci:

<div ng-app="myApp" ng-controller="Ctrl">
<li  ng-repeat="todo in todos">
<input type='checkbox' ng-model="todo.done" ng-click='onCompleteTodo(todo)'>
    {{todo.text}} {{todo.done}}
</li> 
    <hr>
        task: {{current.text}}
        <hr>
            <h2>Wrong value</h2>
         done: {{current.done}}
</div>

Et votre script:

angular.module('myApp', [])
    .controller('Ctrl', ['$scope', function($scope) {

        $scope.todos=[
            {'text': "get milk",
             'done': true
             },
            {'text': "get milk2",
             'done': false
             }
            ];

        $scope.current = $scope.todos[0];


       $scope.onCompleteTodo = function(todo) {
            console.log("onCompleteTodo -done: " + todo.done + " : " + todo.text);
    //$scope.doneAfterClick=todo.done;
    //$scope.todoText = todo.text;
       $scope.current = todo;

   };
}]);

Ce qui est différent ici, c'est que chaque fois que vous cliquez sur une case, cela définit cette case comme ce qui est "actuel" et affiche ensuite ces valeurs dans la vue. http://jsfiddle.net/QeR7y/


0

Cela est généralement dû à une autre directive entre votre ng-controller et votre entrée qui crée une nouvelle portée. Lorsque le select écrit sa valeur, il l'écrira dans la portée la plus récente, de sorte qu'il l'écrira dans cette portée plutôt que dans le parent qui est plus éloigné.

La meilleure pratique est de ne jamais se lier directement à une variable sur la portée dans un ng-model, ceci est également connu comme toujours inclure un "point" dans votre ngmodel. Pour une meilleure explication, regardez cette vidéo de John:

http://www.youtube.com/watch?v=DTx23w4z6Kc

Solution de: https://groups.google.com/forum/#!topic/angular/7Nd_me5YrHU


Ce serait génial si vous fournissez un marqueur de saut #t=5m08sdans votre lien YouTube afin qu'il ne soit pas nécessaire de regarder la vidéo complète. Voir mattcutts.com/blog/link-to-youtube-minute-second
Volker E.

0

Je viens de remplacer ng-modelavec ng-checkedet cela a fonctionné pour moi.

Ce problème s'est produit lorsque j'ai mis à jour ma version angulaire de 1.2.28à1.4.9

Vérifiez également si votre ng-changeproblème est ici. Je devais aussi supprimer mon ng-changepour le faire fonctionner.


-1
.task{ng:{repeat:'task in model.tasks'}}
  %input{type:'checkbox',ng:{model:'$parent.model.tasks[$index].enabled'}}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.