Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the best way to implement a single tri-state checkbox within angularjs?

Is there a simple way to place a single tri-state checkbox on a web-page and bind it to a boolean model so the latter can take true, false or null values?

The closest solution I found so far is http://jsfiddle.net/HB7LU/454/ but it has a flaw when setting up an initial view state (as there is no way to get a model value during first rendering). Any other suggestions deal with multiple child checkboxes and solves the problem by watching on them.

like image 971
user32412 Avatar asked Jan 25 '14 06:01

user32412


3 Answers

http://jsfiddle.net/xJhEG/ I made it in a commercial project. Tristates are true, false, null (not "unknown")

.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);
        });
      }
    };
  }])
like image 173
TruongSinh Avatar answered Oct 09 '22 13:10

TruongSinh


Here my Fiddle, starting from TruongSinh and changing

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

without

var truthy = true;
var falsy = false;
var nully = null;
like image 6
Mauro Sala Avatar answered Oct 09 '22 14:10

Mauro Sala


You have take advantage of the indeterminate state of <input type="checkbox">.

MDN web docs: There exists an indeterminate state of checkboxes, one in which it is not checked or unchecked, but undetermined. This is set using the HTMLInputElement object's indeterminate property via JavaScript (it cannot be set using an HTML attribute).

PLUNKER: TRISTATE DIRECTIVE

HTML

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

DIRECTIVE

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);
        });
      }
    }
  };
});
like image 5
The.Bear Avatar answered Oct 09 '22 13:10

The.Bear