1

I want dynamically set attributes for child directive.
But I can not do it.

In the example I want to set attribute name with value John.

UPD: In this case, I can not determine the exact set of attributes. And I need to define them dynamically. For example, this is part of a third-party library.

angular.module('app', []);

angular.module('app')
  .directive('wrapper', wrapper);

angular.module('app')
  .directive('inWrapper', inWrapper);

angular.bootstrap(
  document.getElementById('root'), ['app']
);

function wrapper() {
  return {
    transclude: true,
    template: '<div ng-transclude></div>',
    link: function linkFn(scope, element, attrs, ctrl,  transcludeFn) {
      transcludeFn(
        scope,
        function(clone) {
          clone.find('in-wrapper').attr('name', 'John');
        }
      );
    }
  }
}

function inWrapper() {
  return {
    scope: {
      name: '@'
    },
    template: 'Hello, {{name}}',
    link: function linkFunc(scope) {
      if (!scope.name) {
        scope.name = 'Empty';
      }
    }
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<div id="root">
  <wrapper>
    <in-wrapper></in-wrapper>
  </wrapper>
</div>

2 Answers 2

1

I tried to set attributes dynamically but failed.
I suggest instead providing data for attributes in the item area directly.
In the code examples, I modified elements inside the transclude function. And provided data for attribute elements in the controller. Code not ideal. Only for demonstration idea.

P.S. Thanks @CodeMonkey for criticizing the original idea

angular.module("app", []);

angular.module("app").directive("wrapper", wrapper);

angular.module("app").directive("inWrapper", inWrapper);

angular.bootstrap(document.getElementById("root"), ["app"]);

function wrapper() {
  return {
    restrict: "E",
    transclude: true,
    controller: function linkFn($scope, $element, $attrs, $transclude) {
      var transcludedContent, transclusionScope,
        statuses = [
          'danger',
          'success',
          'info'
        ];
      status = 0;
      $transclude(function(clone, scope) {
        $element.append(clone);
        transcludedContent = clone;
        transclusionScope = scope;
        for (var i = 0, ii = clone.length; i < ii; i++) {
          var node = clone[i];
          if (node.nodeType !== 3 ||
            node.nodeValue.trim()) {
            node.classList.add(statuses[status]);
            status++;
          }
        }
      });
      // find scope for angulars element and provide data
      var elements = $element.find("in-wrapper");
      for (var i = 0, ii = elements.length; i < ii; i++) {
        var isolateScope = angular.element(elements[i]).isolateScope();
        isolateScope.name = 'World' + isolateScope.$id;

      }

    }
  };
}

function inWrapper() {
  return {
    scope: {
      name: "@"
    },
    template: '<div>Hello, <span ng-bind="name"></span></div>'
  };
}
.danger {
  color: #ff0000;
}

.success {
  color: #00ff00;
}

.info {
  color: #0000ff;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<div id="root">
  <wrapper>
    <in-wrapper></in-wrapper>
    <in-wrapper></in-wrapper>
    <in-wrapper></in-wrapper>
  </wrapper>
</div>

Sign up to request clarification or add additional context in comments.

Comments

0

You should be able to link the attribute to a scope variable. If you are talking about designing the directive yourself, you can define the controller's scope variables as "=" and they will link bidirectionally to the value passed to the attribute. Check the AngularJS: Developer Guide for more info.

You might also be able to assign the value of the attribute using {{...}} annotation to inject a scope variable directly into the markup.

2 Comments

thanks for the reply. I do not need to provide data to child directive. In this case, I can not determine the exact set of attributes. And I need to define them dynamically.
Ah okay. I misunderstood the original question then. Not sure how you would accomplish that. But perhaps a workaround would be to have a single generic attribute that can accept a JSON object and have the directive inspect the properties of the object to determine functionality based on property names?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.