Kliknięcie pola wyboru za pomocą ng-click nie aktualizuje modelu


85

Kliknięcie pola wyboru i wywołanie ng-click: model nie jest aktualizowany przed uruchomieniem ng-click, więc wartość pola wyboru jest nieprawidłowo prezentowana w interfejsie użytkownika:

Działa to w AngularJS 1.0.7 i wydaje się zepsute w 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}}

i kontroler:

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 w / Angular 1.2 RCx - http://jsfiddle.net/supercobra/ekD3r/

Działające skrzypce w / Angular 1.0.0 - http://jsfiddle.net/supercobra/8FQNw/


3
Również zepsuty dla mnie teraz, gdy zaktualizowałem Angular do 1.2+
ac360,

Również uszkodzony w wersji 1.2.24.
Vincent P

Odpowiedzi:


165

Co powiesz na zmianę

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

do

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

Z dokumentów :

Oblicz dane wyrażenie, gdy użytkownik zmieni dane wejściowe. Wyrażenie nie jest oceniane, gdy zmiana wartości pochodzi z modelu.

Uwaga, ta dyrektywa wymaga ngModelobecności.


3
to również wydaje się być zepsute w wersji 1.2.7
JvdBerg

Święta żarówka, Batmanie! Myślałem, że robię coś zupełnie złego, ale okazało się, że jest to takie proste.
Adam Marshall,

1
Bardzo pomocna odpowiedź! +1 Angular doc -1
neurix

co, jeśli potrzebujesz danych zdarzenia, aby zapobiec domyślnemu?
user1943442


9

Kolejność, w jakiej ng-clicki ng-modelzostaną wykonane, jest niejednoznaczna (ponieważ żaden z nich nie ustawił jawniepriority ). Najbardziej stabilnym rozwiązaniem byłoby uniknięcie używania ich na tym samym elemencie.

Ponadto prawdopodobnie nie chcesz zachowania, które pokazują przykłady; chcesz, checkboxaby odpowiadały na kliknięcia całego tekstu etykiety , a nie tylko pola wyboru. Dlatego najczystszym rozwiązaniem byłoby owinięcie input(z ng-model) wewnątrz label(z ng-click):

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

Przykład roboczy: http://jsfiddle.net/b3NLH/1/


Wielkie dzięki! To jedyne rozwiązanie, które mi się sprawdziło!
DaniCE,

To wciąż najlepsze rozwiązanie!
Ellisan

8

Dlaczego nie używasz

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

Innym rozwiązaniem byłoby ustawienie todo.donewewnętrznego wywołania zwrotnego ng-click i używanie tylko 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}}

i

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

2
Zobacz odpowiedź @kakoni, użyłem ng-change zamiast ng-click i synchronizacja działa świetnie. Pozwala to zachować dwukierunkowe wiązanie i jest znacznie czystszym podejściem.
Michael Moser

6

Zastąpienie modelu ng z zaznaczonym ng działa dla mnie.


Właśnie tego chciałem. Dzięki!
Isaac

Po prostu pracował dla mnie ze wszystkich dostępnych tutaj rozwiązań.
thatzprem

2

To rodzaj hackowania, ale umieszczenie go w limicie czasu wydaje się spełniać to, czego szukasz:

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

Kolejność między ng-modeli ng-clickwydaje się być inna i prawdopodobnie nie powinieneś polegać. Zamiast tego możesz zrobić coś takiego:

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

I twój skrypt:

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;

   };
}]);

Różnica polega na tym, że każde kliknięcie pola ustawia to pole jako „bieżące”, a następnie wyświetla te wartości w widoku. http://jsfiddle.net/QeR7y/


0

Zwykle jest to spowodowane inną dyrektywą między kontrolerem ng-controller a danymi wejściowymi, która tworzy nowy zakres. Kiedy select zapisuje swoją wartość, zapisuje ją do najnowszego zakresu, więc zapisuje ją do tego zakresu, a nie do rodzica, który jest dalej.

Najlepszą praktyką jest nigdy nie wiązać się bezpośrednio ze zmienną w zakresie w ng-modelelemencie an , jest to również znane jako zawsze dołączanie „kropki” do ngmodelu. Aby lepiej to wyjaśnić, obejrzyj ten film autorstwa Johna:

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

Rozwiązanie od: https://groups.google.com/forum/#!topic/angular/7Nd_me5YrHU


Byłoby wspaniale, gdybyś podał znacznik skoku #t=5m08sw swoim linku do YouTube, aby nie trzeba było oglądać całego filmu. Zobacz mattcutts.com/blog/link-to-youtube-minute-second
Volker E.

0

Ja po prostu zastąpić ng-modelz ng-checkedi pracował dla mnie.

Ten problem wystąpił, gdy zaktualizowałem moją wersję kątową z 1.2.28do1.4.9

Sprawdź tutaj również, czy ng-changenie powoduje problemów. Musiałem również usunąć moje, ng-changeaby działało.


-1
.task{ng:{repeat:'task in model.tasks'}}
  %input{type:'checkbox',ng:{model:'$parent.model.tasks[$index].enabled'}}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.