angularjsangularjs-componentsangularjs-compile

When using $compile on component, why is the scope passed through $parent?


I'm trying to dynamically compile an Angular component using $compile, but the scope isn't passed to the components scope, but to the $parent scope instead.

Here is a simple component that binds to a myTitle-attribute and presents it:

app.component('myComponent', {
  bindings: {
    myTitle: '<'
  },
  template: `
    <div>
      <div>Doesn't work: {{ $ctrl.myTitle}}</div>
      <div>Works: {{ $parent.$ctrl.myTitle}}</div>
    </div>`
});

Then in the controller (or directive, etc.) I compile it using $compile:

app.controller('MainCtrl', function($scope, $element, $compile) {
  var template = '<my-component></my-component>';
  
  var bindings = {
    myTitle: 'My Title'
  }
  var scope = angular.extend($scope.$new(true), {
    $ctrl: bindings
  });
  var newElement = $compile(template)(scope);
  $element.append(newElement);
  
});

When running this, it yield the result:

Doesn't work:

Works: My Title

Here's a plunker showing it in action

The question

How come the scope I create for the dynamically created component, is passed as a parent scope of the component?

Any pointer on why angular behaves like this and perhaps how to avoid it is much welcome.


Solution

  • As I see, you need to pass binding here var template = '<my-component></my-component>';

    var template = '<my-component my-title="$ctrl.myTitle"></my-component>';
    

    Full component may be like this:

    app.controller('MainCtrl', function($scope, $element, $compile) { 
      var template = '<my-component my-title="$ctrl.myTitle"></my-component>'; 
      $scope.$ctrl = {myTitle: 'My Title'}; 
      $element.append($compile(template)($scope)); 
    });