Установка флажка с помощью 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
11

Как сообщается в https://github.com/angular/angular.js/issues/4765 , переключение с ng-click на ng-change, похоже, исправляет это (я использую Angular 1.2.14)

Питер Холлингсворт
источник
3
Самое простое и легкое решение. +1 к Гриффиндору :)
Somaiah Kumbera
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/

musically_ut
источник
Большое спасибо! Это единственное решение, которое мне помогло!
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.

Zzjove
источник
Как раз то, что я хотел. Благодарность!
Исаак
Просто у меня сработало из всех доступных здесь решений.
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

Fergusrg
источник
Было бы здорово, если бы вы указали маркер перехода #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чтобы он заработал.

Thatzprem
источник
-1
.task{ng:{repeat:'task in model.tasks'}}
  %input{type:'checkbox',ng:{model:'$parent.model.tasks[$index].enabled'}}
Эндрю У. К. Браун
источник