OverviewIn a previous article, we discussed the use of directives to enable claims based authorization on some the user interface elements. For some scenarios, a directive is the ideal approach, but because of the fact that a directive is called every time is declared on the mark-up, it is not ideal for cases where an item lists can have many items, and we just need to validate one or two claims.
Directive ImplementationWhen looking at our previous implementation, we can see on the console windows the number of times that the directive is called. We want to optimize the approach by just calling the directive one time and validate the claims for the user. A way to do this on AngularJS is by using an Isolate Scope Directive. This means that the directive does not share the same scope as the controller, but it also provides the advantages that we can pass object references and functions which can be used to indicate what claims need to be validated all at once thus eliminating the additional calls.New Approach Isolate ScopeNow that we understand our optimization approach, we can refactor our code by first removing the authorize directive from the button markup which is what causes the multiple directive calls. We can now define our new directive with isolate scope and restrict it to “E” which means that it can be used as an element only. The idea here is that we want to declare it only one time on the mark-up outside the ngRepeat scope. We also want to add two attributes to our element. These attributes are assigned to functions within the controller. We should notice that in order to pass evaluating expressions to our directive, the attributes need to be declare with “&”.
scope: { authorizeMapping: '&', authorizeCallback: '&', },//isolate scope
The function assign to the authorize-mapping attribute returns a JSON with all the claims that need to be validated on behalf of that controller. The function assign to the authorize-callback attribute is called by the directive to return the status of each claim (true when found). Let’s take a look at our new implementation:
Controller Kicks InOnce the controller has received the status of each claim, we can leverage the power of AngularJS by mapping claims to controller variables. At this point, we just need to add an ng-show directive and assign a controller variable to evaluate if the user is authorized to see that element. Yes, we are still using a directive for each element, but that is just evaluating a true or false expression, and it is not calling the authorization service to validate the claim.We can now compare the console output with the isolate scope, and we should see that we no longer have multiple calls to our directive. The result should be just one entry.
Does It Work?To check that this is working properly we can run a simple test. Run JSFiddle and set the app.edit claim value to an empty string or just click the delete icon. This should remove the permission on the rest of the list items as shown below.Areas of ImprovementAs usual, we should ask ourselves if there ways of improving this approach. Since we can now notice that this solution uses controller variables, do we really need a directive? If the concern is reusability, the directive approach is preferred over a controller only implementation as this can create code duplication. To show this, we can review the controller only solution on another article.
scope: { authorizeMapping: '&', authorizeCallback: '&', },//isolate scope |