Search code examples
angularjs-scopeangularjs-components

How to set scope for AngularJS component


Suppose I build an AngularJS component

function FooController($scope, $element, $attrs, $http) {
  var ctrl = this;
  ctrl.bar = "WIBBLE";
}

angular.module("app").component("foo", {
    templateUrl: "/app/components/foo.html",
    controller: FooController,
    transclude: true
}

with a template like this that contains a transclusion tag with fallback content

[<ng-transclude>{{$ctrl.bar}}</ng-transclude>]

and I use it in a page like this

<foo></foo>

then the fallback content executes in the control scope and I get this

[WIBBLE]

But if I provide the same stuff via transclusion

<foo>{{$ctrl.bar}}</foo> 

then the transcluded content has a new isolate scope and $ctrl.bar doesn't resolve so I get

[]

How do I set the appropriate scope?

For a directive I would define the link function and use the transclude function to set the scope but component doesn't support the link function so I can't do that.

Why do Angular (1.5) components always have an isolated scope? suggests that it's flat out impossible and the answer is to use a directive instead. If that's so I'm not sure what the point of components is.


Solution

  • You just plain cannot do this for a component. Refactor it as a directive and provide a link function that supplies the directive scope to the transclude function.

            transclude: true, // support <ng-transclude> in the template
            link: function (scope, element, attrs, controller, transclude) {
                var transclusionElement = element.find("ng-transclude");
                transclude(scope, function (clone, scope) {
                    // link element parameter is a jQuery element
                    transclusionElement.html(""); // wipe the slate
                    transclusionElement.append(clone); // write the content
                    // DO NOT TRY TO BE CLEVER LIKE THIS
                    // transclusionElement.html(clone.html());
                });
            },