Search code examples
angularjsparsingangularjs-scopewatchangular-directive

AngularJS - Using a comma or other special character in expression to watch with $scope.$watch


I have a directive that was written a while ago and has been used throughout my application. I have now realised that it needs a watch so it can refresh and update when the value changes.

This is an attribute directive to apply Angular's ngIf directive depending on a user's authorisations. Used in the HTML it looks something like:

<div auth-if="id=12345;CREATE,READ,UPDATE"></div>

The problem I have is with the commas - when I try and watch the attribute value of authIf I get an error

Error: [$parse:syntax] Syntax Error: Token ',' is an unexpected token

Right now I don't know why I didn't just use the letters CRUD but I don't want to change what the directive accepts and potentially break things or cause confusion, etc.

So I was wondering if there is way for me make Angular be happy with the commas?

Here is a simplified version of my directive:

angular.module("myApp").directive("authIf", ["ngIfDirective", "IsAuthorised", function(ngIfDirective, IsAuthorised)
{
    var ngIf = ngIfDirective[0];

    return {
        restrict: "A",
        priority: ngIf.priority - 1,
        terminal: ngIf.terminal,
        transclude: ngIf.transclude,
        link: function(scope, element, attrs)
        {
            var permitted = false;
            // run angular ngIf functionality
            attrs.ngIf = function() {
                return permitted;
            };
            ngIf.link.apply(ngIf, arguments);

            scope.$watch(attrs.authIf, checkAuth);
            function checkAuth() {
                /** check goes here
                    permitted = IsAuthorised(...); **/
            }
        }
    };
});

Solution

  • Since attrs.authIf is invalid expression you may wrap it in a function

    scope.$watch(function() { return attrs.authIf; }, checkAuth);
    

    Working example

    <!DOCTYPE html>
    <html ng-app="app">
    
      <head>
        <script data-require="[email protected]" data-semver="1.4.7" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.js"></script>
    
        <script>
          angular
            .module('app', [])
            .controller('appCtrl', function($scope) {
              $scope.dir = 'initial value';
            })
            .directive('dir', function() {
              return {
                restrict: 'A',
                scope: true,
                link: function(scope, element, attrs) {
                  scope.$watch(function() {
                    return attrs.dir;
                  }, function(newValue) {
                    scope.custom = 'custom ' + newValue;
                  });
                }
              };
            });
        </script>
      </head>
    
      <body ng-controller="appCtrl">
        <h1>Hello Plunker!</h1>
    
        <div dir="id=12345;CREATE,READ,UPDATE">
          {{ custom }}
        </div>
    
        <hr>
    
        <div dir="{{ dir }}">
          {{ custom }}
        </div>
    
        <input type="text" ng-model="dir">
      </body>
    </html>