Tuesday, 1 January 2013

Addon functionality for built-in directives in Angular

In Angular, not only you can create your own directives but also redefine built-in directives to add additional functionality to them. This technique can come in handy in many situations.

Let's see this in action with the built-in form directive. We would like our form, in addition to the standard Angular form directive functionality, to notify its ancestors when it becomes dirty and make itself pristine again when ancestor notifies it to do so.

Here is the fiddle for it.


The markup is usual. There is a div with controller "controller" attached to it and it wraps the form 'myForm' thus becoming ancestor of it. The interesting part is re-declaration of form directive.

myApp.directive('form', [function () {
    return {
        restrict: 'E',
        require: 'form',
        link: function (scope, element, attrs, ctrl) {
            scope.$watch(attrs.name + '.$dirty', 
                function (newValue, oldValue) {
                    if (newValue != oldValue && newValue === true) {
                        scope.$emit('formDirty', attrs.name);
                    } 
                });
            scope.$on('formClean', function () {
                ctrl.$setPristine();             
            });
        }
    };
}]);

Note that we mention 'form' as require value so that Angular FormController associated with the form 'myForm' is made available to our directive. In the link function, a watch is put on form $dirty and an event 'formDirty' is emitted in such case. Also, a listener is added for 'formClean' event that sets the form back to pristine state using FormController.

The controller associated with the wrapper div listens to 'formDirty' event and shows a message on the page when it receives one and it broadcasts 'formClean' event to its descendants when user resets the form using reset button.

Note the ng-disabled attribute has been added to reset button just to show that the all the built-in form directive functionality is available for use.

Note: The $setPristine() API is available only from Angular 1.1.x release.

No comments:

Post a Comment