Facendo clic su una casella di controllo con ng-clic non si aggiorna il modello


85

Facendo clic su una casella di controllo e chiamando ng-click: il modello non viene aggiornato prima che ng-click si attivi, quindi il valore della casella di controllo viene presentato erroneamente nell'interfaccia utente:

Funziona in AngularJS 1.0.7 e sembra non funzionante in 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}}

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

   };
}]);

Violino rotto con Angular 1.2 RCx - http://jsfiddle.net/supercobra/ekD3r/

Fidddle funzionante con Angular 1.0.0 - http://jsfiddle.net/supercobra/8FQNw/


3
Anche per me non funzionante ora che ho aggiornato Angular a 1.2+
ac360

Anche rotto in v1.2.24.
Vincent P

Risposte:


165

Che ne dici di cambiare

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

per

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

Dai documenti :

Valuta l'espressione data quando l'utente modifica l'input. L'espressione non viene valutata quando la modifica del valore proviene dal modello.

Nota, questa direttiva richiede ngModeldi essere presente.


3
anche questo sembra essere rotto nella versione 1.2.7
JvdBerg

Lampadina santa, Batman! Pensavo di fare qualcos'altro di completamente sbagliato, ma si è rivelato semplice come questo.
Adam Marshall

1
Risposta molto utile! +1 Angular doc -1
neurix

cosa succede se hai bisogno dei dati dell'evento per prevenire il valore predefinito?
user1943442


9

L'ordine in cui ng-clicke ng-modelverrà eseguito è ambiguo (poiché nessuno dei due li imposta esplicitamente priority). La soluzione più stabile a questo sarebbe evitare di usarli sullo stesso elemento.

Inoltre, probabilmente non vuoi il comportamento mostrato dagli esempi; si desidera checkboxche risponda ai clic sul testo completo dell'etichetta , non solo sulla casella di controllo. Quindi, la soluzione più pulita sarebbe avvolgere il input(con ng-model) all'interno di un label(con ng-click):

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

Esempio funzionante: http://jsfiddle.net/b3NLH/1/


Molte grazie! Questa è l'unica soluzione che ha funzionato per me!
DaniCE

Questa soluzione è ancora la migliore!
Ellisan,

8

Perché non usi

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

Oppure un'altra soluzione potrebbe essere quella di impostare la todo.donerichiamata interna ng-click e utilizzare solo 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}}

e

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

2
Vedi la risposta di @kakoni, ho usato ng-change invece di ng-click e il tempismo funziona alla grande. Ciò consente di mantenere il legame a due vie ed è un approccio molto più pulito.
Michael Moser

6

La sostituzione di ng-model con ng-verificata funziona per me.


Proprio quello che volevo. Grazie!
Isaac,

Ha funzionato per me da tutte le soluzioni disponibili qui.
thatzprem

2

È una specie di hack, ma avvolgerlo in un timeout sembra ottenere ciò che stai cercando:

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'ordine tra ng-modele ng-clicksembra essere diverso ed è qualcosa su cui probabilmente non dovresti fare affidamento. Invece potresti fare qualcosa del genere:

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

E il tuo 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;

   };
}]);

Ciò che è diverso qui è che ogni volta che fai clic su una casella, imposta quella casella come "corrente" e quindi mostra quei valori nella vista. http://jsfiddle.net/QeR7y/


0

Di solito ciò è dovuto a un'altra direttiva tra il tuo ng-controller e il tuo input che sta creando un nuovo ambito. Quando la selezione scrive il valore, lo scriverà fino all'ambito più recente, quindi lo scriverà in questo ambito anziché nel genitore che è più lontano.

La migliore pratica è non legare mai direttamente a una variabile sull'ambito in un ng-model, questo è anche noto come includere sempre un "punto" nel tuo ngmodel. Per una migliore spiegazione di questo, guarda questo video di John:

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

Soluzione da: https://groups.google.com/forum/#!topic/angular/7Nd_me5YrHU


Sarebbe fantastico se fornissi un indicatore di salto #t=5m08snel tuo link YouTube, quindi non è necessario guardare il video completo. Vedi mattcutts.com/blog/link-to-youtube-minute-second
Volker E.

0

Ho appena sostituito ng-modelcon ng-checkeded ha funzionato per me.

Questo problema si è verificato quando ho aggiornato la mia versione angolare da 1.2.28a1.4.9

Controlla anche se stai ng-changecausando problemi qui. Ho dovuto rimuovere anche il mio ng-changeper farlo funzionare.


-1
.task{ng:{repeat:'task in model.tasks'}}
  %input{type:'checkbox',ng:{model:'$parent.model.tasks[$index].enabled'}}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.