web-dev-qa-db-fra.com

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

En cliquant sur une case à cocher et en appelant ng-click: le modèle n'est pas mis à jour avant que ng-click n'entre en action de sorte que la valeur de la case à cocher est présentée de manière erroné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;

   };
}]);

Cassé Fiddle avec Angular 1.2 RCx - http://jsfiddle.net/supercobra/ekD3r/

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

83
supercobra

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">

De docs :

É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 requiert que ngModel soit présent.

157
kakoni

Comme indiqué dans https://github.com/angular/angular.js/issues/4765 , le passage de ng-click à ng-change semble résoudre ce problème (j'utilise Angular 1.2.14).

11

L'ordre dans lequel ng-click et ng-model seront exécutés est ambigu (car aucun d'entre eux n'a explicitement défini sa priority). La solution la plus stable serait d'éviter de les utiliser sur le même élément. 

En outre, vous ne voulez probablement pas le comportement que les exemples montrent; vous voulez que la variable checkbox réponde aux clics sur l'intégralité du texte label, et pas uniquement sur la case à cocher. Par conséquent, la solution la plus propre serait d’envelopper la input (avec ng-model) dans une 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/

8
musically_ut

Pourquoi n'utilisez-vous pas 

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

Une autre solution consiste à définir le todo.done dans le rappel ng-click et à n’utiliser que 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;
}
8
GuillaumeA

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

6
zzjove

C'est un peu un bidouillage, mais l'enrouler dans un délai semble donner ce que vous cherchez:

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;
        });
    };
}]);
2
Brian Lewis

L'ordre entre ng-model et ng-click semble être différent et c'est quelque chose sur lequel vous ne devriez probablement pas compter. 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, elle la définit comme "actuelle", puis affiche ces valeurs dans la vue. http://jsfiddle.net/QeR7y/

1
Manny D

Je viens de remplacer ng-model par ng-checked et cela a fonctionné pour moi.

Ce problème était lorsque j'ai mis à jour ma version angulaire de 1.2.28 à 1.4.9 

Vérifiez également si votre ng-change est à l’origine d’un problème ici. J'ai dû retirer mon ng-change ainsi pour le faire fonctionner.

0
thatzprem

Cela est généralement dû à une autre directive entre votre contrôleur ng et votre contribution qui crée une nouvelle portée. Lorsque la sélection écrit sa valeur, il l'écrira à la portée la plus récente, donc l'écrirait dans cette portée plutôt que le parent qui est plus loin une façon. 

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

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

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

0
fergusrg