การคลิกช่องทำเครื่องหมายด้วย ng-click จะไม่อัปเดตโมเดล


85

การคลิกที่ช่องทำเครื่องหมายและเรียกใช้ ng-click: โมเดลไม่ได้รับการอัปเดตก่อนที่จะเริ่มการคลิกที่ ng-click ดังนั้นค่าช่องทำเครื่องหมายจึงแสดงใน UI ไม่ถูกต้อง:

สิ่งนี้ใช้ได้ใน 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;

   };
}]);

Broken Fiddle พร้อม 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 ด้วย
Vincent P

คำตอบ:


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

หลอดไฟศักดิ์สิทธิ์แบทแมน! ฉันคิดว่าฉันทำอย่างอื่นผิดไปหมด แต่มันกลายเป็นเรื่องง่ายอย่างนี้
Adam Marshall

1
คำตอบที่เป็นประโยชน์มาก! +1 Angular doc -1
neurix

จะเกิดอะไรขึ้นถ้าคุณต้องการข้อมูลเหตุการณ์เพื่อป้องกันไม่ให้ Default?
user1943442

11

ตามรายงานในhttps://github.com/angular/angular.js/issues/4765 การเปลี่ยนจาก ng-click เป็น ng-change ดูเหมือนจะแก้ไขปัญหานี้ได้ (ฉันใช้ Angular 1.2.14)


3
แก้ไขง่ายที่สุดและง่ายที่สุด +1 ถึง Griffindor :)
Somaiah Kumbera

9

ลำดับที่ng-clickและng-modelจะดำเนินการนั้นไม่ชัดเจน (เนื่องจากไม่ได้ตั้งค่าไว้อย่างชัดเจนpriority) วิธีแก้ปัญหาที่เสถียรที่สุดคือหลีกเลี่ยงการใช้งานในองค์ประกอบเดียวกัน

นอกจากนี้คุณอาจไม่ต้องการพฤติกรรมที่ตัวอย่างแสดง คุณต้องการcheckboxให้ตอบสนองต่อการคลิกบนข้อความป้ายกำกับทั้งหมดไม่ใช่เฉพาะช่องทำเครื่องหมาย ดังนั้นวิธีแก้ปัญหาที่สะอาดที่สุดคือการห่อinput(ด้วยng-model) ภายในlabel(ด้วยng-click):

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

ตัวอย่างการทำงาน: http://jsfiddle.net/b3NLH/1/


ขอบคุณมาก! นี่เป็นทางออกเดียวที่ใช้ได้ผลกับฉัน!
DaniCE

วิธีนี้ยังดีที่สุด!
Ellisan

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 และเวลาทำงานได้ดี วิธีนี้ช่วยให้คุณสามารถผูกได้สองทางและเป็นแนวทางที่สะอาดกว่ามาก
Michael Moser

6

การเปลี่ยน ng-model ด้วยการตรวจสอบ ng ใช้งานได้สำหรับฉัน


สิ่งที่ฉันต้องการ ขอบคุณ!
Isaac

เพิ่งทำงานให้ฉันจากโซลูชันที่มีอยู่ทั้งหมดที่นี่
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-controller และอินพุตของคุณซึ่งกำลังสร้างขอบเขตใหม่ เมื่อสิ่งที่เลือกเขียนค่านั้นมันจะเขียนถึงขอบเขตล่าสุดดังนั้นมันจะเขียนลงในขอบเขตนี้แทนที่จะเป็นพาเรนต์ที่อยู่ไกลออกไป

แนวทางปฏิบัติที่ดีที่สุดคืออย่าผูกโดยตรงกับตัวแปรในขอบเขตใน an ng-modelซึ่งเรียกอีกอย่างว่ารวม "จุด" ไว้ใน ngmodel ของคุณเสมอ หากต้องการคำอธิบายที่ดีขึ้นโปรดดูวิดีโอจาก John:

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ด้วยเพื่อให้มันใช้งานได้


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.