0

Assume this directive:

<validation-errors field="someField">Some errors: {{errors}}</validation-errors>

I thought I could create the directive function simple as this:

    return {
        require: '^form',
        restrict: 'E',
        link: link,
        scope: {
            field: '@'
        },
        transclude: true,
        template: '<span ng-show="errors" class="alert-danger" ng-transclude></span>'
    };

    function link(scope, el, attr, ctrl, transcludeFn) {
        scope.errors = ctrl.Validator.getErrors(attr.field);
    }

But since Transclusion is the process of extracting a collection of DOM element from one part of the DOM and copying them to another part of the DOM, while maintaining their connection to the original AngularJS scope from where they were taken. (from docs), the scope doesn't work like I thought it would.

So I tried this which works, except that the "Some errors" part is duplicated:

transcludeFn(function(clone, transScope) {
    scope.errors = transScope.errors = ctrl.Validator.getErrors(attr.field);
    el.append(clone);
});

It doesn't work if I remove el.append(clone);.

What's the best way to make the transcluded content share the directive template's scope?

Markus Hedlund
  • 23,374
  • 22
  • 80
  • 109

1 Answers1

0

If you want to create the errors using the directive, give something like this a try, I've updated the code so that it compiles the template as well, now working exactly as the ng-transclude directive would out of the box.

'use strict';

/* Directives */

angular.module('myApp.directives', []).
directive('errordirective', ['$compile',function($compile) {
  return {
    restrict: 'E',
    scope: {
      field: '@',
    },
    transclude: true,
    //Create some error text
    controller: function() {
      this.errorText = "Some Errors We Created";
      //Make the template available to the link fn, and make it an angular element.
      this.template = angular.element('<span class="alert-danger" ng-transclude></span>')
    },
    //Make the controller available easily
    controllerAs: 'Errors',
    //Bind the scope properties to the controller, only works with controllerAs
    bindToController: true,
    template: '<span class="alert-danger" ng-transclude></span>',
    link: function(scope, elem, attrs, ctrl, transcludefn) {
      //Replace the original element with the new one that has the error text from our controller
      transcludefn(scope, function(el) {
        var template = ctrl.template;
        var html = el.html();
        //Add the transcluded content to the template
        template.html(html);
        //Compile the template with the appropriate scope
        template = $compile(template)(scope);
        //Replace with the new template
        elem.replaceWith(template);

      });
    }

  };
}]);
richbai90
  • 4,994
  • 4
  • 50
  • 85
  • Sorry but the transcludeFn code goes in the link function. `errors` is in other words created in the directive. – Markus Hedlund Jul 10 '15 at 18:56
  • I've updated my answer to suit your needs. The errors is now being created in the directive. Right now it is being created statically in the controller but you could do any amount of manipulation to it within the link function. – richbai90 Jul 10 '15 at 19:25
  • Nice thanks, but now you are removing/replacing the template `` – Markus Hedlund Jul 13 '15 at 07:41
  • This should do everything you want it to do, I'm using `$compile` so you don't lose your template. – richbai90 Jul 13 '15 at 14:35