1

DEMO

Here is a simplified version of the two directives I have, my-input and another-directive:

HTML:

<body ng-controller="AppCtrl">
  <another-directive>
    <my-input my-input-model="data.firstName"></my-input>
  </another-directive>
</body>

JS:

.directive('myInput', function() {
  return {
    restrict: 'E',
    replace: true,
    scope: {
      model: '=myInputModel'
    },
    template: '<input type="text" ng-model="model">'
  };
}).directive('anotherDirective', function($compile) {
  return {
    restrict: 'E',
    scope: {},
    compile: function(element) {
      var html = element.html();

      return function(scope) {
        var output = angular.element(
          '<div class="another-directive">' +
            html +
          '</div>'
        );

        $compile(output)(scope);
        element.empty().append(output); // This line breaks the binding
      };
    }
  };
});

As you can see in the demo, if I remove element.empty().append(output);, everything works fine, i.e. changes in the input field are reflected in controller's data. But, adding this line, breaks the binding.

Why is this happening?

PLAYGROUND HERE

3 Answers 3

2

The element.empty() call is destroying all child nodes of element. In this case, element is the html representation of another-directive. When you are calling .empty() on it, it is trying to destroy its child directive my-input and any scopes/data-bindings that go with it.

A somewhat unrelated note about your example. You should look into using transclusion to nest html within a directive, like you are doing with another-directive. You can find more info here: https://docs.angularjs.org/api/ng/service/$compile#transclusion

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

Comments

1

I think a little bit context as to what you are trying to do well be helpful. I am assuming you want to wrap the my-input directive in another-directive ( some sort of parent pane ). You could accomplish this using ng transclude. i.e

angular.module('App', []).controller('AppCtrl', function($scope) {
  $scope.data = {
    firstName: 'David'
  };
  $scope.test = "My test data";
}).directive('myInput', function() {
  return {
    restrict: 'E',
    replace: true,
    scope: {
      model: '=myInputModel'
    },
    template: '<input type="text" ng-model="model">'
  };
}).directive('anotherDirective', function($compile) {
  return {
    restrict: 'E',
    transclude: true,
    scope: {},
    template : '<div class="another-directive"><div ng-transclude></div></div>' 
    };
});

Comments

0

It works if you require ngModel

}).directive('anotherDirective', function($compile) {
return {
  restrict: 'E',
  require:'ngModel',
  scope: {},
...

Comments

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.