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/

Superkobra
quelle
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.

Kakoni
quelle
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
11

Wie unter https://github.com/angular/angular.js/issues/4765 berichtet , scheint der Wechsel von ng-click zu ng-change dies zu beheben (ich verwende Angular 1.2.14).

Peter Hollingsworth
quelle
3
Einfachste und einfachste Lösung. +1 zu Griffindor :)
Somaiah Kumbera
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/

musikalisch_ut
quelle
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;
}
GuillaumeA
quelle
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.

zzjove
quelle
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;
        });
    };
}]);
Brian Lewis
quelle
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/

Manny D.
quelle
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

fergusrg
quelle
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.

thatzprem
quelle
-1
.task{ng:{repeat:'task in model.tasks'}}
  %input{type:'checkbox',ng:{model:'$parent.model.tasks[$index].enabled'}}
Andrew WC Brown
quelle