AngularJS: How to create a translatable element directive that preserves attribute directives and can add new ones?

I have been working on this issue for two days now. I feel it should be a lot easier.

Description of the problem

I would like to create a directive that is used as follows:

<my-directive ng-something="something">
    content
</my-directive>

and has an output:

<my-directive ng-something="something" ng-more="more">
    content
</my-directive>

Naturally, he would have a binding function and a controller that do a certain job, but the main problems are:

  • that the DOM element retains its original name so that you can apply an intuitive CSS style,
  • that existing attribute attributes continue to work properly, and
  • that new attribute directives can be added by the element directive itself.

Example

For example, let's say I want to create an element that does something internally when clicked:

<click-count ng-repeat="X in ['A', 'B', 'C']"> {{ X }} </click-count>

- :

<click-count ng-click="internalFn()"> A </click-count>
<click-count ng-click="internalFn()"> B </click-count>
<click-count ng-click="internalFn()"> C </click-count>

internalFn clickCount.

- Plunker: http://plnkr.co/edit/j9sUUS?p=preview

Plunker, , , :

angular.module('app', []).directive('clickCount', function() {
  return {
    restrict: 'E',
    replace: true,
    transclude: true,
    scope: {
      ccModel: '='
    },
    compile: function(dElement) {
      dElement.attr("ngClick", "ccModel = ccModel + 1");

      return function postLink($scope, iElement, iAttrs, controller, transclude) {
        transclude(function(cloned) { iElement.append(cloned); });
      };
    },
    controller: function ($scope) {
        $scope.ccModel = 0;
    }
  };
});

HTML- :

<!DOCTYPE html>
<html>
<head>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.13/angular.js"></script>
  <link rel="stylesheet" href="style.css" />
  <script src="script.js"></script>
</head>
<body ng-app="app">
  <hr> The internal 'ng-click' doesn't work:
  <click-count ng-repeat="X in ['A', 'B', 'C']" cc-model="counter">
    {{ X }}, {{ counter }}
  </click-count>
  <hr> But an external 'ng-click' does work:
  <click-count ng-repeat="X in ['A', 'B', 'C']" cc-model="bla" ng-init="counter = 0" ng-click="counter = counter + 1">
    {{ X }}, {{ counter }}
  </click-count>
  <hr>
</body>
</html>

, css :

click-count {
  display: block;
  border: solid 1px;
  background-color: lightgreen;
  font-weight: bold;
  margin: 5px;
  padding: 5px;
}

, , . , , $compile, . , , , .

+4
1

, DOM , . , . Angular priority. 0, , , . , , ngRepeat 1000, terminal:true, , ngRepeat, . , , ngRepeat. ngClick:

angular.module('app', []).directive('clickCount', function() {
  return {
    restrict: 'E',
    replace: true,
    compile: function(tElement) {
      return {
        pre: function(scope, iElement) {
          iElement.attr('ng-click', 'counter = counter +1'); // <- Add attribute
        },
        post: function(scope, iElement) {
          iElement.on('click', function() { // <- Add behavior
            scope.$apply(function(){ // <- Since scope variables may be modified, don't forget to apply the scope changes
              scope.$eval(iElement.attr('ng-click')); // <- Evaluate expression defined in ng-click attribute in context of scope
            });
          });
        }
      }
    }
  };
});

JSBin: http://jsbin.com/sehobavo/1/edit

ngRepeat:

angular.module('app', []).directive('clickCount', function($compile) {
  return {
    restrict: 'E',
    replace: true,
    compile: function(tElement) {
      return {
        pre: function(scope, iElement) {
          if(iElement.attr('ng-repeat')) { // <- Avoid recursion
            iElement.attr('ng-click', 'counter = counter +1'); // <- Add custom attributes and directives
            iElement.removeAttr('ng-repeat'); // <- Avoid recursion
            $compile(iElement)(scope); // <- Recompile your element to make other directives work
          }
        }
      }
    }
  };
});

JSBin: http://jsbin.com/hucunuqu/4/edit

+1

Source: https://habr.com/ru/post/1527940/


All Articles