如果使用了preventDefault,则AngularJS复选框已检查无法呈现

时间:2015-05-16 18:01:23

标签: javascript angularjs checkbox

我正在动态构建一组复选框。单击任何选中的复选框应取消选中第一个(索引方式)复选框。单击任何未选中的复选框应检查最后一个未选中的复选框。

我正在使用ng-repeat构建复选框,如下所示:

<input
  type="checkbox"
  ng-checked="values[$index]"
  ng-repeat="n in values track by $index" 
  ng-click="click($event,$index)" />

我的控制器看起来像这样:

.controller("myCtrl", function ($scope) {

$scope.values = [true,true,true,true];

$scope.click = function (event,n) {
  event.preventDefault();
  if ($scope.values[n] === true) {
    $scope.values[$scope.values.indexOf(true)] = false;
  } else {
    $scope.values[$scope.values.lastIndexOf(false)] = true;
  }
}

以下是http://codepen.io/anon/pen/rVLewJ

的代码

我遇到的问题是使用preventDefault似乎阻止了ng-checked更新了你点击的框的渲染(其他框正确地重新渲染)。这会导致显示与$ scope.values不同步。

同样,删除preventDefault并不会阻止你点击的框更改其渲染,但是(我相信因为ng-repeat的保守重新渲染)ng-checked不会触发,所以它也会从同步。

我没有使用ng-changed,因为我特意试图阻止复选框如果你点击“错误”的复选框。无论如何,我尝试使用它而不是ng-clicked并且它没有修复任何东西。 我尝试使用ng-model而不是ng-checked,但这似乎阻止了$ scope.values的改变。使用$ scope。$ apply(),没有帮助。我读过的一些内容让我觉得我可能需要使用$watch,但我正在教自己Angular这个项目,所以我不确定如何应用它。

更新

Nagasimha Iyengar提供了一个工作解决方案here,我已经简化了

<input
       type="checkbox"
       ng-model="values[$index]"
       ng-repeat="n in values track by $index" 
       ng-change="click($index)" />

控制器:

.controller("myCtrl", function ($scope) {

$scope.values = [true,true,true,true];

$scope.click = function (n) {
  if ($scope.values[n] === true) {//clicking on unchecked box
    $scope.values[n] = false;
    $scope.values[$scope.values.lastIndexOf(false)] = true;
  } else {//clicking on checked box
    $scope.values[n] = true;
    $scope.values[$scope.values.indexOf(true)] = false;
  }
}

Codepen:http://codepen.io/anon/pen/zGBKxr

此解决方案基于允许click事件发生,然后在继续使用自定义逻辑之前撤消它。这当然是一个简单的解决方案,但感觉有点不合适。这是解决这个问题最正确的方法吗?

另一个小小的更新。我放弃了ngTouch试图让应用程序在移动设备上感觉更快一些。至少在iOS Safari 8中,ngTouch打破了这个解决方案。在桌面上仍然可以正常工作,但重写的ngClick会阻止此解决方案表单工作。如果你切换回原来建议的逻辑它修复iOS,但当然不能在桌面上工作。我觉得这证实了我的怀疑,即解决方案不正确。

2 个答案:

答案 0 :(得分:1)

这是 - 逻辑被逆转了。我使用$ apply超时。修改后的代码:http://codepen.io/nagasimhai/pen/VLjjPe

angular
.module("myApp", [])
    .controller("myCtrl", function ($scope) {

    $scope.values = [true,true,true,true];

    $scope.click = function (event,n) {
      //event.preventDefault();
      //console.log("b", n, $scope.values,$scope.values.indexOf(true), $scope.values.lastIndexOf(false));
      if ($scope.values[n] === true) {//clicking on unchecked box
        $scope.values[n] = false;
        $scope.values[$scope.values.lastIndexOf(false)] = true;
        //console.log("11");
      } else {//clicking on checked box
        $scope.values[n] = true;
        $scope.values[$scope.values.indexOf(true)] = false;
        //console.log('22');

      }
      //console.log("a",n, $scope.values);
      setTimeout(function () {
        $scope.$apply(function () {

        });
    }, 2000);
    }
});

答案 1 :(得分:0)

你的回答有点令人困惑,但我相信我走的是正确的道路。问题。您想要使用的是event.stopPropagation()来阻止事件传播。换句话说,您只希望将事件应用于特定元素。如果使用event.preventDefault(),则取消该事件(如果可取消),而不会停止事件的进一步传播

angular
.module("myApp", [])
.controller("myCtrl", function ($scope) {

$scope.values = [true,true,true,true];

$scope.click = function (event,n) {
  event.stopPropagation();
  if ($scope.values[n] === true) {
    $scope.values[$scope.values.indexOf(true)] = false;
    $scope.values[n] = false;
  } else {
    $scope.values[$scope.values.lastIndexOf(false)] = true;
  }
}
});

在codepen http://codepen.io/anon/pen/bdepPW

中尝试输出代码