Pro AngularJS, Chapter 17, $formatters and $parsers

HTML

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap-theme.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js"></script>
<script type="text/ng-template" id="triTemplate">
    <div class = "well">
        <div class="btn-group">
            <button class = "btn btn-default">Yes</button>
            <button class="btn btn-default">No</button>
            <button class = "btn btn-default">Not Sure</button>
        </div>
        <span class="error" ng-show ="myForm.decision.$error.confidence" > You need to be sure</span>
    </div>
</script>
<body ng-app="exampleApp" ng-controller="defaultCtrl">
    <form name="myForm" novalidate>
        <div>
            <tri-button name="decision" ng-model="dataValue" />
        </div>
    </form>
    <div class="well">Value:
        <select ng-model="dataValue">
            <option>Yes</option>
            <option>No</option>
            <option>Not Sure</option>
            <option>Huh?</option>
        </select>
    </div>
</body>

JavaScript

var myApp = angular.module("exampleApp", []);

myApp.controller("defaultCtrl", function ($scope) {
    $scope.dataValue = "Not Sure";
})
    .directive("triButton", function () {
    return {
        restrict: "E",
        replace: true,
        require: "ngModel",
        template: document.querySelector("#triTemplate").outerText,
        link: function (scope, element, attrs, ctrl) {

            var buttons = element.find("button"),
                setSelected = function (value) {

                    buttons.removeClass("btn-primary");

                    for (var i = 0; i < buttons.length; i++) {
                        if (buttons.eq(i).text() === value) {
                            buttons.eq(i).addClass("btn-primary");
                        }
                    }
                },
                validateParser = function (value) {
                    var valid = (value == "Yes" || value == "No");
                    ctrl.$setValidity("confidence", valid);
                    
                    return valid ? value : undefined;
                };
            
            ctrl.$render = function () {
                var val = ctrl.$viewValue;
                
                validateParser(val);
                setSelected(val || "Not Sure");
            };
            
            ctrl.$formatters.push(function (value) {
                return value == "Huh?" ? "Not Sure" : value;
            });
            ctrl.$parsers.push(validateParser);

            buttons.on("click", function (event) {
                var val = event.target.innerText;

                setSelected(val);
                scope.$apply(function () {
                    ctrl.$setViewValue(val);
                });
            });
        }
    }
});