Установка флажка с помощью ng-click не обновляет модель


85

Щелчок по флажку и вызов ng-click: модель не обновляется до срабатывания ng-click, поэтому значение флажка неверно отображается в пользовательском интерфейсе:

Это работает в AngularJS 1.0.7 и кажется неработающим в 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}}

и контроллер:

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;

   };
}]);

Сломанный скрипт с Angular 1.2 RCx - http://jsfiddle.net/supercobra/ekD3r/

Рабочий скрипт с Angular 1.0.0 - http://jsfiddle.net/supercobra/8FQNw/


3
Также сломан для меня теперь, когда я обновил Angular до
1.2+

Также сломан в v1.2.24.
Винсент П.

Ответы:


165

Как насчет изменения

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

к

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

Из документов :

Оценить данное выражение, когда пользователь изменяет ввод. Выражение не оценивается, когда изменение значения исходит от модели.

Обратите внимание: эта директива ngModelдолжна присутствовать.


3
похоже, что это тоже не работает в версии 1.2.7
JvdBerg 08

Святая лампочка, Бэтмен! Я думал, что делаю что-то еще совершенно неправильно, но оказалось, что все очень просто.
Адам Маршалл

1
Очень полезный ответ! +1 Angular doc -1
Neurix

что, если вам нужны данные о событии для предотвращения дефолта?
user1943442


9

Порядок , в котором ng-clickи ng-modelбудет выполняться неоднозначно (так как ни явно не установить их priority). Наиболее стабильным решением этой проблемы было бы избегать их использования в одном элементе.

Кроме того, вам, вероятно, не нужно поведение, которое показывают примеры; вы хотите, checkboxчтобы он реагировал на щелчки по всему тексту метки , а не только по флажку. Следовательно, самым чистым решением было бы обернуть input(with ng-model) внутри label(with ng-click):

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

Рабочий пример: http://jsfiddle.net/b3NLH/1/


Большое спасибо! Это единственное решение, которое мне помогло!
DaniCE

Это решение до сих пор остается лучшим!
Эллисан

8

Почему ты не используешь

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

Или другим решением было бы установить todo.doneвнутренний обратный вызов ng-click и использовать только 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}}

а также

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

2
См. Ответ @kakoni, я использовал ng-change вместо ng-click, и время отлично работает. Это позволяет сохранить двустороннюю привязку и является гораздо более чистым подходом.
Майкл Мозер

6

У меня работает замена ng-model на ng-checked.


Как раз то, что я хотел. Благодарность!
Исаак

Просто у меня сработало из всех доступных здесь решений.
thatzprem

2

Это своего рода хакерский прием, но, заключив его в тайм-аут, кажется, можно добиться того, что вы ищете:

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

Порядок между ng-modelи ng-clickкажется другим, и на это вам, вероятно, не стоит полагаться. Вместо этого вы можете сделать что-то вроде этого:

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

И ваш сценарий:

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;

   };
}]);

Здесь разница в том, что всякий раз, когда вы щелкаете по полю, он устанавливает это поле как «текущее», а затем отображает эти значения в представлении. http://jsfiddle.net/QeR7y/


0

Обычно это происходит из-за другой директивы между вашим ng-контроллером и вашим вводом, которая создает новую область. Когда select записывает это значение, он будет записывать его до самой последней области, поэтому он будет записывать его в эту область, а не в родительский объект, который находится дальше.

Лучшая практика - никогда не связываться напрямую с переменной в области видимости в ng-modelобъекте, это также известно как включение «точки» в вашу модель ngmodel. Чтобы лучше понять это, посмотрите это видео от Джона:

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

Решение от: https://groups.google.com/forum/#!topic/angular/7Nd_me5YrHU


Было бы здорово, если бы вы указали маркер перехода #t=5m08sв своей ссылке на YouTube, чтобы не было необходимости смотреть полное видео. См. Mattcutts.com/blog/link-to-youtube-minute-second
Volker E.

0

Я просто заменил ng-modelна, ng-checkedи у меня это сработало.

Эта проблема возникла, когда я обновил свою угловую версию с 1.2.28на1.4.9

Также проверьте, ng-changeне вызываете ли вы здесь какие-либо проблемы. Мне пришлось снять и мой, ng-changeчтобы он заработал.


Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.