Какой лучший способ реализовать один флажок с тремя состояниями в angularjs?

Существует ли простой способ разместить один флажок с тремя состояниями на веб-странице и связать его с булевой моделью, чтобы последняя могла принять true, false или же null ценности?

Самое близкое решение, которое я нашел до сих пор, это http://jsfiddle.net/HB7LU/454/ но у него есть недостаток при настройке начального состояния просмотра (так как нет способа получить значение модели во время первого рендеринга). Любые другие предложения касаются нескольких дочерних флажков и решают проблему, наблюдая за ними.

5 ответов

Решение

http://jsfiddle.net/xJhEG/ Я сделал это в коммерческом проекте. Тристаты - это правда, ложь, ноль (не "неизвестно")

.directive('indeterminate', [function() {
    return {
      require: '?ngModel',
      link: function(scope, el, attrs, ctrl) {
        var truthy = true;
        var falsy = false;
        var nully = null;
        ctrl.$formatters = [];
        ctrl.$parsers = [];
        ctrl.$render = function() {
          var d = ctrl.$viewValue;
          el.data('checked', d);
          switch(d){
          case truthy:
            el.prop('indeterminate', false);
            el.prop('checked', true);
            break;
          case falsy:
            el.prop('indeterminate', false);
            el.prop('checked', false);
            break;
          default:
            el.prop('indeterminate', true);
          }
        };
        el.bind('click', function() {
          var d;
          switch(el.data('checked')){
          case falsy:
            d = truthy;
            break;
          case truthy:
            d = nully;
            break;
          default:
            d = falsy;
          }
          ctrl.$setViewValue(d);
          scope.$apply(ctrl.$render);
        });
      }
    };
  }])

Вот моя скрипка, начиная с TruongSinh и меняя

http://jsfiddle.net/xJhEG/25/

без

var truthy = true;
var falsy = false;
var nully = null;

Вы должны воспользоваться неопределенным состоянием <input type="checkbox">,

Веб-документы MDN: существует неопределенное состояние флажков, в которых оно не отмечено или не проверено, но не определено. Это устанавливается с помощью неопределенного свойства объекта HTMLInputElement через JavaScript (его нельзя установить с помощью атрибута HTML).

ПЛАНКЕР: ТРИСТАТ ДИРЕКТИВ

HTML

<label>
    <input type="checkbox" ng-model="state" indeterminate /> {{state}}
</label>

ДИРЕКТИВА

app.directive('indeterminate', function() {
  return {
    restrict: 'A',
    scope: {
      model: '=ngModel'
    },
    link: function(scope, el, attrs, ctrl) {
      var states = [true, false, undefined];
      var index = states.indexOf(scope.model);
      setIndeterminate();

      el.bind('click', function() {
        scope.model = states[++index % 3];
        setIndeterminate();
      });

      function setIndeterminate() {
        scope.$applyAsync(function() {
          el[0].indeterminate = (scope.model === undefined);
        });
      }
    }
  };
});

ДОПОЛНИТЕЛЬНО: Если вы хотите добавить строку для представления неопределенного состояния, используйте этот CSS

input:indeterminate:after {
  content: "indeterminate";
  padding-left: 20px;
  display: inline-block;
  width: 80px;
}

Я создал директиву, которую вы можете использовать. Флажок с тремя состояниями AngularJS Директива на GitHub

Также есть пост о том, как он был построен: " Создание Директивы Ангулра" Флажок с тремя состояниями

Вы можете попробовать ДЕМО

И директива выглядит так:

angular.module("threeStateCheckbox", [])
    .directive("threeStateCheckbox", ['$compile', function($compile){
        return {
            restrict: "A",
            transclude: true,
            require: 'ngModel',
            link: function(scope, element, attrs, ngModel){
                var states = [true, false, null];
                var classNames = ["checked", "unchecked", "clear"];
                scope.click = function(){
                    var st;
                    states.map(function(val, i){
                        if(ngModel.$modelValue === val){
                            st = states[(i+1)%3];
                        }
                    });
                    ngModel.$setViewValue(st);
                    ngModel.$render();
                };
                scope.tscClassName = function(){
                    var className;
                    states.map(function(val, i){
                        if(ngModel.$modelValue=== val){
                            className = classNames[i];
                        }
                    });
                    return className;
                };
                element.attr("class", "tri-sta-che ");
                element.attr("ng-click", "click()");
                element.attr("ng-class", "tscClassName()");
                element.removeAttr("three-state-checkbox");
                $compile(element)(scope);
            }
        };
    }]);

Поскольку все предыдущие ответы не работают, начиная с AngularJS 1.7 (модель флажка теперь допускает только логические значения, а все остальное преобразуется в логические), теперь я нашел решение, которое работает до версии 1.8: спасибо @The.Bear за базу .

Чтобы использовать его, просто включите <tristate label="someOptionalText" ng-model="yourVariableToBindTo" />и соответствующую директиву.

Другие вопросы по тегам