Back to Devblog

ng-Tri-Toggle, an AngularJS Triple-State Checkbox Directive

on 1 min read

Determining the “Indeterminate” Issue

You already know exactly what issue I’m referring to if you’ve ever tried to use a checkbox input with the indeterminate state for something other than a nested checklist. The scenarios are extremely rare, but when come across, people resort to strange ways of creating three way toggleable checkboxes, and hacky select inputs. In Nozzle’s specific situation, we needed a checkbox that could harness 2 “active” or toggleable values, and an off or null state. This would allow us to essentially “turn on” a filter that my have two “on” states eg. an off state, a true state, and a false state.

A custom directive. Simple and elegant.

Here, I forewent dealing with checkboxes and select inputs all together, and focused on using angular’s magical databinding and directives to get the job done. Click here for the github repo! The AngularJS Triple-State Checkbox
The HTML in your template

<tri-toggle ng-model="myValue"></tri-toggle>

Results in a toggle capable of three states:

ng-tri-toggle

This is the Javascript you don’t see:

  var ngTriToggle = angular.module('ngTriToggle', []);
  ngTriToggle
      .directive('triToggle', function($timeout) {
          return {
              restrict: 'E',
              replace: false,
              transclude: true,
              scope: {
                  ngChange: '&',
                  val: '=ngModel',
                  ngTrueVal: '=?',
                  ngngFalseVal: '=?',
                  ngNoVal: '=?',
                  tanner: '&'
              },
              template: '<div class="tri-toggle-wrap" ng-class="{\'true\': val==ngTrueVal, \'false\': val==ngFalseVal}" ng-click="toggle()"><div class="tri-toggle-false" ng-click="toggleFalse()"></div><div class="tri-toggle-true" ng-click="toggleTrue()"></div><div class="tri-toggle-handle" ng-click="toggleNone()"></div></div>',
              link: function(scope) {

                  if (!angular.isDefined(scope.ngTrueVal)) {
                      scope.ngTrueVal = 1;
                  }
                  if (!angular.isDefined(scope.ngFalseVal)) {
                      scope.ngFalseVal = 0;
                  }
                  if (!angular.isDefined(scope.ngNoVal)) {
                      scope.ngNoVal = null;
                  }

                  if (!angular.isDefined(scope.val)) {
                      scope.val = scope.ngNoVal;
                  }

                  scope.toggle = function() {
                      if (scope.val === scope.ngTrueVal) {
                          scope.val = scope.ngFalseVal;
                      } else if (scope.val === scope.ngFalseVal) {
                          scope.val = scope.ngNoVal;
                      } else {
                          scope.val = scope.ngTrueVal;
                      }
                      if (typeof scope.ngChange != 'undefined') {
                          $timeout(function() {
                              scope.ngChange(scope.val);
                          });
                      }
                  };
              },
          };
      });

It gives you the option to define custom true, false and null values:

  <tri-toggle
      ng-model="myValue"
      ng-true-val="1"
      ng-false-val="0"
      ng-no-val="-1">
  </tri-toggle>

And also gives you a handy callback:

  <tri-toggle
      ng-change="myFunction()"
      ng-model="myValue"
  </tri-toggle>

Note: This callback is not a watcher. To detect programmatic changes to your model, set up a $scope.$watch('myValue') on your ng-model variable. That’s It!

Now it’s super easy to create as many tri-toggles as you want with absolutely zero checkbox or select input hacking!

Enjoy!

Wait! Our data robots are chomping at their bits to get your free trial started, so don't let them down!
Enter your email below to save them from their electronic sorrow and start your trial!