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

by Tanner Linsley on Jul 3, 2014 - 2 minute 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:

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!

Personas:
Tanner Linsley

Tanner loves front-end development and spends most of his day in Javascript and React. Occasionally he designs as well, and even likes to record some music every now and then, but nothing is more exciting to him than building a new open source framework, or surfing Github.

Like what you see?

Take Nozzle for spin for 2 weeks for free!

or

Call 1-855-NOZZLE1

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!
×