1

我正在尝试构建一个不使用<input type="checkbox">. 它应该按预期工作;更新模型应该更新视图,单击框应该更新模型,它应该听required指令(验证应该起作用)。

我目前有以下指令,完全按预期工作:

'use strict';

angular.module('directives.checkbox', [])
  .directive('checkbox', [function () {
    return {
      restrict: 'A',
      require: 'ngModel',
      replace: true,
      template: '<span class="checkbox"></span>',
      link: function (scope, elem, attrs, ctrl) {
        elem.bind('click', function () {
          scope.$apply(function () {
            elem.toggleClass('checked');
            ctrl.$setViewValue(elem.hasClass('checked'));
          });
        });

        ctrl.$render = function () {
          if (!elem.hasClass('checked') && ctrl.$viewValue) {
            elem.addClass('checked');
          } else if (elem.hasClass('checked') && !ctrl.$viewValue) {
            elem.removeClass('checked');
          }
        };
      }
    }
  }]);

它只是一个<span>带有一个 CSS 类checkbox和另一个checked用于选中状态的 CSS 类。但是,使用 jQuery 来切换类并像我一样更新视图似乎不太像 Angular(或最佳实践)。我宁愿使用ng-classandng-click指令,但这意味着我需要使用隔离范围(以避免在同一页面上使用多个复选框时范围状态冲突)。出于某种原因,孤立的范围使角度停止调用$render()ctrl

有谁知道这是否是正确的方法,或者是否有一种更像角度的方法仍然可以解决我的要求?

4

3 回答 3

1

首先,我相信如果样式是您的问题,您绝对可以通过 css 自定义输入而不是创建必须模仿输入复选框的指令。

话虽如此,添加和删除类的角度方式实际上是将 then 作为表达式或作为 ngClass 的参数包含在模板中。您还可以通过在模板中包含 ngClick 来避免绑定。

app.directive('myCheckbox', function() {
  return {
    restrict: 'E',
    replace: true,
    transclude: true,
    template: '<span class="checkbox" ng-class="{checked: isChecked}" ng-click="toggleMe()"></span>',
    scope: { isChecked: '=?'},
    link: function(scope, elem, attrs) {
      scope.isChecked = true;

    scope.toggleMe = function() {
        scope.isChecked = !(scope.isChecked);
    }
 }
 });

这是一个小笨蛋来解释我的意思

于 2013-12-26T19:42:10.667 回答
0

未为复选框调用 $render 函数。除了提供渲染功能,我们还可以观察模型变化并检查元素状态并相应地更新 UI。

下面是指令代码。

var app = angular.module('RadioOrCheck', []);

app.controller('MainCtrl', function($scope) {
  $scope.name = 'World';
});

app.directive('radioOrCheck', radioOrCheckDirective);

function radioOrCheckDirective() {
  return {
    require: 'ngModel',
    restrict: 'A',
    scope: false,
    link: link
  };

  function link(scope, element, attrs) {
    element.addClass('hidden-input').wrap('<label/>');
    element.parent().addClass(attrs.type).append('<span/>');

    scope.$watch(attrs.ngModel, function updateUI() {
      element.parent().toggleClass('checked', jQuery(element).is(':checked'));
    });

    attrs.$observe('label', function(newLabel) {
      element.parent().find('span').text(newLabel);
    });
  }
}
.hidden-input {
  border: 0;
  clip: rect(0 0 0 0);
  height: 0;
  margin: 0;
  overflow: hidden;
  padding: 0;
  position: absolute;
  width: 0;
}
.radio {
  display: block;
  cursor: pointer;
  color: red;
}
.radio.checked {
  color: green;
}
.checkbox {
  display: block;
  cursor: pointer;
  color: red;
}
.checkbox.checked {
  color: green;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

<div ng-app="RadioOrCheck">
<input radio-or-check="" type="checkbox" ng-model="cbModel" data-label="CB Label" />
<br/>
<input radio-or-check="" type="checkbox" ng-model="cbModel" data-label="CB Label" />
<br/>
<input radio-or-check="" type="checkbox" ng-model="cbModel" data-label="CB Label" />
<br/>
<br/>
<input radio-or-check="" type="radio" ng-model="rModel" data-label="R Label" value="1" />
<br/>
<input radio-or-check="" type="radio" ng-model="rModel" data-label="R Label" value="2" />
<br/>
<input radio-or-check="" type="radio" ng-model="rModel" data-label="R Label" value="3" />
<br/>
</div>

这是正在工作的 plunker。这里的输入字段是模拟默认的,CSS 可以根据您的需要进行调整。

于 2016-09-05T07:06:18.983 回答
0

未为复选框调用 $render 函数。除了提供渲染功能,我们还可以观察模型变化并检查元素状态并相应地更新 UI。

下面是指令代码。

var app = angular.module('RadioOrCheck', []);

app.controller('MainCtrl', function($scope) {
  $scope.name = 'World';
});

app.directive('radioOrCheck', radioOrCheckDirective);

function radioOrCheckDirective() {
  return {
    require: 'ngModel',
    restrict: 'A',
    scope: false,
    link: link
  };

  function link(scope, element, attrs) {
    element.addClass('hidden-input').wrap('<label/>');
    element.parent().addClass(attrs.type).append('<span/>');

    scope.$watch(attrs.ngModel, function updateUI() {
      element.parent().toggleClass('checked', jQuery(element).is(':checked'));
    });

    attrs.$observe('label', function(newLabel) {
      element.parent().find('span').text(newLabel);
    });
  }
}
.hidden-input {
  border: 0;
  clip: rect(0 0 0 0);
  height: 0;
  margin: 0;
  overflow: hidden;
  padding: 0;
  position: absolute;
  width: 0;
}
.radio {
  display: block;
  cursor: pointer;
  color: red;
}
.radio.checked {
  color: green;
}
.checkbox {
  display: block;
  cursor: pointer;
  color: red;
}
.checkbox.checked {
  color: green;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<input radio-or-check="" type="checkbox" ng-model="cbModel" data-label="CB Label" />
<br/>
<input radio-or-check="" type="checkbox" ng-model="cbModel" data-label="CB Label" />
<br/>
<input radio-or-check="" type="checkbox" ng-model="cbModel" data-label="CB Label" />
<br/>
<br/>
<input radio-or-check="" type="radio" ng-model="rModel" data-label="R Label" value="1" />
<br/>
<input radio-or-check="" type="radio" ng-model="rModel" data-label="R Label" value="2" />
<br/>
<input radio-or-check="" type="radio" ng-model="rModel" data-label="R Label" value="3" />
<br/>

这是正在工作的 plunker。这里的输入字段是模拟默认的,CSS 可以根据您的需要进行调整。

于 2016-09-05T07:02:47.597 回答