Tutorial 18.2 Directive Decorator Example

******************************************INDEX.HTML*****************************************************
<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Example - example-directive-decorator-production</title>
 

  <script src="//code.angularjs.org/snapshot/angular.min.js"></script>
  <script src="script.js"></script>
 

 
</head>
<body ng-app="urlDecorator">
  <div ng-controller="Ctrl">
  <a ng-href="/products/{{ id }}/view" id="id3">View Product {{ id }}</a>
  - <strong>id === 3</strong>, so no warning<br>
  <a ng-href="/products/{{ id + 5 }}/view" id="id8">View Product {{ id + 5 }}</a>
  - <strong>id + 5 === 8</strong>, so no warning<br>
  <a ng-href="/products/{{ someOtherId }}/view" id="someOtherId">View Product {{ someOtherId }}</a>
  - <strong style="background-color: #ffff00;">someOtherId === undefined</strong>, so warn<br>
  <a ng-href="/products/{{ someOtherId + 5 }}/view" id="someOtherId5">View Product {{ someOtherId + 5 }}</a>
  - <strong>someOtherId + 5 === 5</strong>, so no warning<br>
  <div>Warn Count: {{ warnCount }}</div>
</div>
</body>
</html>


******************************************INDEX.HTML*****************************************************
********************************************script.js***************************************************
(function(angular) {
  'use strict';
angular.module('urlDecorator', []).

  controller('Ctrl', ['$scope', function($scope) {
    $scope.id = 3;
    $scope.warnCount = 0; // for testing
  }]).

  config(['$provide', function($provide) {

    // matchExpressions looks for interpolation markup in the directive attribute, extracts the expressions
    // from that markup (if they exist) and returns an array of those expressions
    function matchExpressions(str) {
      var exps = str.match(/{{([^}]+)}}/g);

      // if there isn't any, get out of here
      if (exps === null) return;

      exps = exps.map(function(exp) {
        var prop = exp.match(/[^{}]+/);
        return prop === null ? null : prop[0];
      });

      return exps;
    }

    // remember: directives must be selected by appending 'Directive' to the directive selector
    $provide.decorator('ngHrefDirective', [
      '$delegate',
      '$log',
      '$parse',
      function($delegate, $log, $parse) {

        // store the original link fn
        var originalLinkFn = $delegate[0].link;

        // replace the compile fn
        $delegate[0].compile = function(tElem, tAttr) {

          // store the original exp in the directive attribute for our warning message
          var originalExp = tAttr.ngHref;

          // get the interpolated expressions
          var exps = matchExpressions(originalExp);

          // create and store the getters using $parse
          var getters = exps.map(function(exp) {
            return exp && $parse(exp);
          });

          return function newLinkFn(scope, elem, attr) {
            // fire the originalLinkFn
            originalLinkFn.apply($delegate[0], arguments);

            // observe the directive attr and check the expressions
            attr.$observe('ngHref', function(val) {

              // if we have getters and getters is an array...
              if (getters && angular.isArray(getters)) {

                // loop through the getters and process them
                angular.forEach(getters, function(g, idx) {

                  // if val is truthy, then the warning won't log
                  var val = angular.isFunction(g) ? g(scope) : true;
                  if (!val) {
                    $log.warn('NgHref Warning: "' + exps[idx] + '" in the expression "' + originalExp +
                      '" is falsy!');

                    scope.warnCount++; // for testing
                  }

                });

              }

            });

          };

        };

        // get rid of the old link function since we return a link function in compile
        delete $delegate[0].link;

        // return the $delegate
        return $delegate;

      }

    ]);

  }]);
})(window.angular);

/*
Copyright 2019 Google Inc. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at http://angular.io/license
*/

********************************************script.js***************************************************

******************************************Protractor.js*****************************************************
it('should warn when an expression in the interpolated value is falsy', function() {
  var id3 = element(by.id('id3'));
  var id8 = element(by.id('id8'));
  var someOther = element(by.id('someOtherId'));
  var someOther5 = element(by.id('someOtherId5'));

  expect(id3.getText()).toEqual('View Product 3');
  expect(id3.getAttribute('href')).toContain('/products/3/view');

  expect(id8.getText()).toEqual('View Product 8');
  expect(id8.getAttribute('href')).toContain('/products/8/view');

  expect(someOther.getText()).toEqual('View Product');
  expect(someOther.getAttribute('href')).toContain('/products//view');

  expect(someOther5.getText()).toEqual('View Product 5');
  expect(someOther5.getAttribute('href')).toContain('/products/5/view');

  expect(element(by.binding('warnCount')).getText()).toEqual('Warn Count: 1');
});

******************************************Protractor.js*****************************************************

Comments

Popular posts from this blog

Tutorial 12.12 Creating a Directive that Wraps Other Elements 3

Tutorial 12.14 Creating Directives that Communicate