fodma1 fodma1 - 28 days ago 19
AngularJS Question

Custom compile function removes two way binding

I have an attribute directive

my-directive
in my Angular 1.5.8 app. I want to add it to an element and also I'd like to pass two extra parameters, one with
one-way
binding (
@
), the other with
two-way
binding (
=
).

It works fine until I try to customize the directive's compile function to add extra attributes. The
one-way
binding still works fine, but the
two-way
binding just disappears.

Here's the plunk.

If I comment out the compile function, it works again. I guess I'm overwriting the default behavior somehow, but I can't figure out how to prevent that.

My compile function:

compile: function compile(element, attrs) {
return {
pre: function preLink(scope, iElement, iAttrs, controller) {},
post: function postLink(scope, iElement, iAttrs, controller) {
if (!iAttrs.compiled) {
iElement.attr('compiled', true);
iElement.attr('ng-click', "$ctrl.onClick()");
$compile(iElement)(scope);
}
}
};
}

Answer

I don't have a precise answer for why this is behaving like that but the compile will only works on children elements with your current set. So you can solve the problem by just changing your $compile(... to the following code.

$compile(iElement.children())(scope);

UPDATE 1

Apearently the iElement has its scope already defined by the parent scope. Threrefore, the compile will not be able use the element because the isolated scope only works within the directive.

However, the issue now is how to add new directives in compile phase? I could do this by changinf your directive to the following code:

.directive('myDirective', function($compile) {
    return {
      terminal: true,
      priority: 1001,
      restrict: 'A',
      scope: {
        myObject: '=myObject',
        text: '@text'
      },
      transclude: true,
      bindToController: true,
      controller: function() {
        var $ctrl = this;
        $ctrl.onClick = onClick;
        return $ctrl;

        function onClick() {
          alert("clicked");
        }
      },
      controllerAs: '$ctrl',
      template: '<pre>{{$ctrl}}</pre> {{ $ctrl.text }} - {{ $ctrl.myObject.attr1 }}',
      compile: function compile(element, attrs) {
        element.removeAttr("my-directive");
        element.attr('compiled', true);
        element.attr('ng-click', "$ctrl.onClick()");
        return {
          pre: function preLink(scope, iElement, iAttrs, controller) {},
          post: function postLink(scope, iElement, iAttrs, controller) {
            $compile(iElement)(scope);
          }
        };
      }
    };
  });