Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJS: What's the best practice to add ngIf to a directive programmatically?

I want to create a directive that checks if an element should be present in the dom based on a value coming from a service (e.g. check for a user role).

The corresponding directive looks like this:

angular.module('app', []).directive('addCondition', function($rootScope) {     return {         restrict: 'A',         compile: function (element, attr) {           var ngIf = attr.ngIf,               value = $rootScope.$eval(attr.addCondition);            /**            * Make sure to combine with existing ngIf!            * I want to modify the expression to be evalued by ngIf here based on a role             * check for example            */           if (ngIf) {             value += ' && ' + ngIf;           }            attr.$set('ng-if', value);         }     }; }); 

At the end the element has the ng-if attribute attached but somehow it doesn't apply to the element and it is still existing in the dom. So this is obviously a wrong approach.

This fiddle shows the problem: http://jsfiddle.net/L37tZ/2/

Who can explain why this happens? Is there any other way a similar behaviour could be achieved? Existing ngIfs should be considered.

SOLUTION:

Usage: <div rln-require-roles="['ADMIN', 'USER']">I'm hidden when theses role requirements are not satifisfied!</div>

.directive('rlnRequireRoles', function ($animate, Session) {    return {     transclude: 'element',     priority: 600,     terminal: true,     restrict: 'A',     link: function ($scope, $element, $attr, ctrl, $transclude) {       var block, childScope, roles;        $attr.$observe('rlnRequireRoles', function (value) {         roles = $scope.$eval(value);         if (Session.hasRoles(roles)) {           if (!childScope) {             childScope = $scope.$new();             $transclude(childScope, function (clone) {               block = {                 startNode: clone[0],                 endNode: clone[clone.length++] = document.createComment(' end rlnRequireRoles: ' + $attr.rlnRequireRoles + ' ')               };               $animate.enter(clone, $element.parent(), $element);             });           }         } else {            if (childScope) {             childScope.$destroy();             childScope = null;           }            if (block) {             $animate.leave(getBlockElements(block));             block = null;           }         }       });     }   }; }); 

It is very important to add the priority in the directive, otherwise other directives attached to that element are not evaluated!

like image 861
Foobar Avatar asked Dec 02 '13 10:12

Foobar


People also ask

How does ngIf work in AngularJS?

The ng-if Directive in AngularJS is used to remove or recreate a portion of the HTML element based on an expression. The ng-if is different from the ng-hide directive because it completely removes the element in the DOM rather than just hiding the display of the element.

What is the use of ngIf directive?

The ngIf directive removes or recreates a portion of the DOM tree based on an {expression}. If the expression assigned to ngIf evaluates to a false value then the element is removed from the DOM, otherwise a clone of the element is reinserted into the DOM.

What is difference between ngIf and Ng-Show directive?

ng-if can only render data whenever the condition is true. It doesn't have any rendered data until the condition is true. ng-show can show and hide the rendered data, that is, it always kept the rendered data and show or hide on the basis of that directives.

Can we use ngIf and Ng-show together?

ng-if is better in this regard. Using it in place of ng-show will prevent the heavy content from being rendered in the first place if the expression is false. However, its strength is also its weakness, because if the user hides the chart and then shows it again, the content is rendered from scratch each time.


1 Answers

You can reuse ngIf in your own directive like this:

/** @const */ var NAME = 'yourCustomIf';  yourApp.directive(NAME, function(ngIfDirective) {   var ngIf = ngIfDirective[0];    return {     transclude: ngIf.transclude,     priority: ngIf.priority,     terminal: ngIf.terminal,     restrict: ngIf.restrict,     link: function($scope, $element, $attr) {       var value = $attr[NAME];       var yourCustomValue = $scope.$eval(value);        $attr.ngIf = function() {         return yourCustomValue;       };       ngIf.link.apply(ngIf, arguments);     }   }; }); 

and then use it like this

<div your-custom-if="true">This is shown</div> 

and it will use all the "features" that come with using ngIf.

like image 110
Joscha Avatar answered Oct 10 '22 01:10

Joscha