[javascript] Add directives from directive in AngularJS

Here's a solution that moves the directives that need to be added dynamically, into the view and also adds some optional (basic) conditional-logic. This keeps the directive clean with no hard-coded logic.

The directive takes an array of objects, each object contains the name of the directive to be added and the value to pass to it (if any).

I was struggling to think of a use-case for a directive like this until I thought that it might be useful to add some conditional logic that only adds a directive based on some condition (though the answer below is still contrived). I added an optional if property that should contain a bool value, expression or function (e.g. defined in your controller) that determines if the directive should be added or not.

I'm also using attrs.$attr.dynamicDirectives to get the exact attribute declaration used to add the directive (e.g. data-dynamic-directive, dynamic-directive) without hard-coding string values to check for.

Plunker Demo

_x000D_
_x000D_
angular.module('plunker', ['ui.bootstrap'])_x000D_
    .controller('DatepickerDemoCtrl', ['$scope',_x000D_
        function($scope) {_x000D_
            $scope.dt = function() {_x000D_
                return new Date();_x000D_
            };_x000D_
            $scope.selects = [1, 2, 3, 4];_x000D_
            $scope.el = 2;_x000D_
_x000D_
            // For use with our dynamic-directive_x000D_
            $scope.selectIsRequired = true;_x000D_
            $scope.addTooltip = function() {_x000D_
                return true;_x000D_
            };_x000D_
        }_x000D_
    ])_x000D_
    .directive('dynamicDirectives', ['$compile',_x000D_
        function($compile) {_x000D_
            _x000D_
             var addDirectiveToElement = function(scope, element, dir) {_x000D_
                var propName;_x000D_
                if (dir.if) {_x000D_
                    propName = Object.keys(dir)[1];_x000D_
                    var addDirective = scope.$eval(dir.if);_x000D_
                    if (addDirective) {_x000D_
                        element.attr(propName, dir[propName]);_x000D_
                    }_x000D_
                } else { // No condition, just add directive_x000D_
                    propName = Object.keys(dir)[0];_x000D_
                    element.attr(propName, dir[propName]);_x000D_
                }_x000D_
            };_x000D_
            _x000D_
            var linker = function(scope, element, attrs) {_x000D_
                var directives = scope.$eval(attrs.dynamicDirectives);_x000D_
        _x000D_
                if (!directives || !angular.isArray(directives)) {_x000D_
                    return $compile(element)(scope);_x000D_
                }_x000D_
               _x000D_
                // Add all directives in the array_x000D_
                angular.forEach(directives, function(dir){_x000D_
                    addDirectiveToElement(scope, element, dir);_x000D_
                });_x000D_
                _x000D_
                // Remove attribute used to add this directive_x000D_
                element.removeAttr(attrs.$attr.dynamicDirectives);_x000D_
                // Compile element to run other directives_x000D_
                $compile(element)(scope);_x000D_
            };_x000D_
        _x000D_
            return {_x000D_
                priority: 1001, // Run before other directives e.g.  ng-repeat_x000D_
                terminal: true, // Stop other directives running_x000D_
                link: linker_x000D_
            };_x000D_
        }_x000D_
    ]);
_x000D_
<!doctype html>_x000D_
<html ng-app="plunker">_x000D_
_x000D_
<head>_x000D_
    <script src="//code.angularjs.org/1.2.20/angular.js"></script>_x000D_
    <script src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.6.0.js"></script>_x000D_
    <script src="example.js"></script>_x000D_
    <link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/css/bootstrap-combined.min.css" rel="stylesheet">_x000D_
</head>_x000D_
_x000D_
<body>_x000D_
_x000D_
    <div data-ng-controller="DatepickerDemoCtrl">_x000D_
_x000D_
        <select data-ng-options="s for s in selects" data-ng-model="el" _x000D_
            data-dynamic-directives="[_x000D_
                { 'if' : 'selectIsRequired', 'ng-required' : '{{selectIsRequired}}' },_x000D_
                { 'tooltip-placement' : 'bottom' },_x000D_
                { 'if' : 'addTooltip()', 'tooltip' : '{{ dt() }}' }_x000D_
            ]">_x000D_
            <option value=""></option>_x000D_
        </select>_x000D_
_x000D_
    </div>_x000D_
</body>_x000D_
_x000D_
</html>
_x000D_
_x000D_
_x000D_

Examples related to javascript

need to add a class to an element How to make a variable accessible outside a function? Hide Signs that Meteor.js was Used How to create a showdown.js markdown extension Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Summing radio input values How to execute an action before close metro app WinJS javascript, for loop defines a dynamic variable name Getting all files in directory with ajax

Examples related to angularjs

AngularJs directive not updating another directive's scope ERROR in Cannot find module 'node-sass' CORS: credentials mode is 'include' CORS error :Request header field Authorization is not allowed by Access-Control-Allow-Headers in preflight response WebSocket connection failed: Error during WebSocket handshake: Unexpected response code: 400 Print Html template in Angular 2 (ng-print in Angular 2) $http.get(...).success is not a function Angular 1.6.0: "Possibly unhandled rejection" error Find object by its property in array of objects with AngularJS way Error: Cannot invoke an expression whose type lacks a call signature

Examples related to model-view-controller

Vue JS mounted() Content type 'application/x-www-form-urlencoded;charset=UTF-8' not supported for @RequestBody MultiValueMap Display List in a View MVC What exactly is the difference between Web API and REST API in MVC? No default constructor found; nested exception is java.lang.NoSuchMethodException with Spring MVC? Spring MVC Missing URI template variable What is difference between MVC, MVP & MVVM design pattern in terms of coding c# Add directives from directive in AngularJS No mapping found for HTTP request with URI Spring MVC Limiting number of displayed results when using ngRepeat

Examples related to mvvm

Vue.js—Difference between v-model and v-bind Pass command parameter to method in ViewModel in WPF? [Vue warn]: Cannot find element Binding an Image in WPF MVVM Binding ComboBox SelectedItem using MVVM What is difference between MVC, MVP & MVVM design pattern in terms of coding c# How to make all controls resize accordingly proportionally when window is maximized? Add directives from directive in AngularJS Wpf DataGrid Add new row Close Window from ViewModel

Examples related to angularjs-directive

Angular2 - Input Field To Accept Only Numbers Use of symbols '@', '&', '=' and '>' in custom directive's scope binding: AngularJS ng-change not working on a text input Controller not a function, got undefined, while defining controllers globally Find child element in AngularJS directive Angular directives - when and how to use compile, controller, pre-link and post-link How to validate email id in angularJs using ng-pattern Enable/Disable Anchor Tags using AngularJS get original element from ng-click How to detect browser using angularjs?