<form ng-app="app" name="form" class="form-horizontal" ng-controller="ExampleController"> <div control-group label="Example"> <input type="text" id="example" name="example" ng-model="data.example" required /> </div> </form>
var app = angular.module("app", []); app.directive("controlGroup", function () { return { template: '<div class="control-group" ng-class="{ error: isError }">\ <label class="control-label" for="{{for}}">{{label}}</label>\ <div class="controls" ng-transclude></div>\ </div>', replace: true, transclude: true, require: "^form", scope: { label: "@" // Gets the string contents of the `label` attribute }, link: function (scope, element, attrs, formController) { // The <label> should have a `for` attribute that links it to the input. // Get the `id` attribute from the input element // and add it to the scope so our template can access it. var id = element.find(":input").attr("id"); scope.for = id; // Get the `name` attribute of the input var inputName = element.find(":input").attr("name"); // Build the scope expression that contains the validation status. // e.g. "form.example.$invalid" var errorExpression = [formController.$name, inputName, "$invalid"].join("."); // Watch the parent scope, because current scope is isolated. scope.$parent.$watch(errorExpression, function (isError) { scope.isError = isError; }); } }; }); app.controller("ExampleController", ["$scope", function ($scope) { $scope.data = { example: "" }; }]);