Durch Klicken auf ein Kontrollkästchen mit ng-click wird das Modell nicht aktualisiert


85

Klicken Sie auf ein Kontrollkästchen und rufen Sie ng-click auf: Das Modell wird nicht aktualisiert, bevor ng-click aktiviert wird, sodass der Wert des Kontrollkästchens in der Benutzeroberfläche falsch angezeigt wird:

Dies funktioniert in AngularJS 1.0.7 und scheint in Angualar 1.2-RCx fehlerhaft zu sein.

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

und Controller:

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;

   };
}]);

Broken Fiddle mit Angular 1.2 RCx - http://jsfiddle.net/supercobra/ekD3r/

Working Fidddle mit Angular 1.0.0 - http://jsfiddle.net/supercobra/8FQNw/


3
Auch für mich jetzt kaputt, da ich Angular auf 1.2+ aktualisiert habe
ac360

Auch in v1.2.24 kaputt.
Vincent P

Antworten:


165

Wie wäre es mit Veränderung

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

zu

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

Aus Dokumenten :

Bewerten Sie den angegebenen Ausdruck, wenn der Benutzer die Eingabe ändert. Der Ausdruck wird nicht ausgewertet, wenn die Wertänderung aus dem Modell stammt.

Beachten Sie, dass diese Richtlinie ngModelvorhanden sein muss.


3
Dies scheint auch in Version 1.2.7
JvdBerg

Heilige Glühbirne, Batman! Ich dachte, ich mache etwas völlig anderes falsch, aber es stellte sich als so einfach heraus.
Adam Marshall

1
Sehr hilfreiche Antwort! +1 Angular doc -1
Neurix

Was ist, wenn Sie die Ereignisdaten benötigen, um Default zu verhindern?
user1943442


9

Die Reihenfolge, in der ng-clickund ng-modelausgeführt wird, ist nicht eindeutig (da beide nicht explizit ihre festlegenpriority ). Die stabilste Lösung hierfür wäre, zu vermeiden, dass sie für dasselbe Element verwendet werden.

Außerdem möchten Sie wahrscheinlich nicht das Verhalten, das die Beispiele zeigen. Sie möchten checkbox, dass auf Klicks auf den vollständigen Beschriftungstext reagiert wird , nicht nur auf das Kontrollkästchen. Daher wäre die sauberste Lösung, das input(mit ng-model) in ein label(mit ng-click) zu wickeln :

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

Arbeitsbeispiel: http://jsfiddle.net/b3NLH/1/


Vielen Dank! Dies ist die einzige Lösung, die bei mir funktioniert hat!
DaniCE

Diese Lösung ist immer noch die beste!
Ellisan

8

Warum benutzt du nicht?

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

Oder eine andere Lösung wäre, das todo.doneInnere des ng-click-Rückrufs festzulegen und nur ng-click zu verwenden

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

und

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

2
Siehe @ kakoni Antwort, ich habe ng-change anstelle von ng-click verwendet und das Timing funktioniert hervorragend. Auf diese Weise können Sie die bidirektionale Bindung beibehalten und sind viel sauberer.
Michael Moser

6

Das Ersetzen des ng-Modells durch das ng-check funktioniert bei mir.


Genau das, was ich wollte. Vielen Dank!
Isaac

Ich habe gerade mit allen verfügbaren Lösungen hier gearbeitet.
Thatzprem

2

Es ist eine Art Hack, aber das Einwickeln in eine Auszeit scheint das zu erreichen, wonach Sie suchen:

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

Die Reihenfolge zwischen ng-modelund ng-clickscheint unterschiedlich zu sein und darauf sollten Sie sich wahrscheinlich nicht verlassen. Stattdessen könnten Sie so etwas tun:

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

Und dein Drehbuch:

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;

   };
}]);

Was hier anders ist, ist, wenn Sie auf ein Feld klicken, dieses Feld als "aktuell" festzulegen und diese Werte dann in der Ansicht anzuzeigen. http://jsfiddle.net/QeR7y/


0

Normalerweise liegt dies an einer anderen Anweisung zwischen Ihrem ng-Controller und Ihrer Eingabe, die einen neuen Bereich erstellt. Wenn die Auswahl den Wert ausschreibt, wird er in den neuesten Bereich geschrieben, sodass er in diesen Bereich und nicht in den weiter entfernten übergeordneten Bereich geschrieben wird.

Die beste Vorgehensweise besteht darin, niemals direkt an eine Variable im Bereich in einem zu binden ng-model Dies wird auch als immer ein "Punkt" in Ihrem ngmodel bezeichnet. Eine bessere Erklärung hierfür finden Sie in diesem Video von John:

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

Lösung von: https://groups.google.com/forum/#!topic/angular/7Nd_me5YrHU


Es wäre großartig, wenn Sie #t=5m08sin Ihrem YouTube-Link einen Sprungmarker bereitstellen würden, damit Sie nicht das vollständige Video ansehen müssen. Siehe mattcutts.com/blog/link-to-youtube-minute-second
Volker E.

0

Ich habe gerade ersetzt ng-modelmitng-checked und es funktionierte für mich.

Dieses Problem trat auf, als ich meine Winkelversion von 1.2.28auf aktualisierte1.4.9

Überprüfen Sie ng-changehier auch, ob Ihr Problem auftritt. Ich musste auch meine entfernen ng-change, damit es funktionierte.


-1
.task{ng:{repeat:'task in model.tasks'}}
  %input{type:'checkbox',ng:{model:'$parent.model.tasks[$index].enabled'}}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.