Angular Bootstrap Control Group

http://angularjs.org/

by Martin Večeřa

HTML

<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css">
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.8/angular.min.js"></script>
<div ng-controller="myController">
    <form name="myForm">
        <div class="form-group">
            <label class="control-label">Enter your name:</label>
            <input type="text" class="form-control span2" name="name" ng-required="true" ng-model="model.name" placeholder="Lowercase only" ng-pattern="/^[a-z]*$/" />
        </div>
    </form>Debug:
    <dl> <dt>model.name</dt>

        <dd>Name: {{model.name}}</dd> <dt>Form Valid:</dt>

        <dd>{{myForm.$valid}}</dd> <dt>Field Valid:</dt>

        <dd>{{myForm.name.$valid}}</dd>
    </dl>
</div>

JavaScript

var app = angular.module("myApp", []);
app.controller("myController", function ($scope) {
    $scope.model = {
        name: ""
    };
});

app.directive("formGroup", function () {
    return {
        restrict: "C",
        //get the controller in the link function
        require: "formGroup",
        link: function ($scope, element, attributes, controller) {
            var errorList = {};
            controller.inputError = function () {
                element.addClass("has-error");
            };
            controller.inputValid = function () {
                element.removeClass("has-error");
            };
        },
        //the controller is initialized in link function
        controller: function() {return {};}
    };
});

app.directive("input", function () {
    return {
        restrict: "E",
        //require controlllers of ngModel and parent directive
        //formGroup
        //they're injected as array parameter of link function
        require: ["?ngModel", "^?formGroup"],
        link: function ($scope, element, attributes, controllers) {
            var modelController = controllers[0];
            var formGroupController = controllers[1];
            if (!modelController || !formGroupController) return;
            var hasBeenVisited = false;
            // check if user has left the field
            element.on("blur", function () {
                $scope.$apply(function () {
                    hasBeenVisited = true;
                });
            });
            // Watch the validity of the input
            $scope.$watch(function () {
                return modelController.$invalid && hasBeenVisited;
            }, function () {
                // $emit messages to the control group
                if (modelController.$invalid && hasBeenVisited) {
                    formGroupController.inputError();
                } else {
                    formGroupController.inputValid();
                }
            });
        }
    };
});