Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Transclude in scope #14303

Open
wytrych opened this issue Mar 22, 2016 · 2 comments
Open

Transclude in scope #14303

wytrych opened this issue Mar 22, 2016 · 2 comments

Comments

@wytrych
Copy link

wytrych commented Mar 22, 2016

I have come to use this pattern quite often:

An isolated scope directive with transclusion providing some $scope methods and properties with a default template that has UI elements using these methods.

For example:

module.directive('myDirective',
        function () {
            return {
                restrict: 'A',
                transclude: true,
                scope: {},
                templateUrl: 'templates/my-directive.html',
                link: function ($scope, $element, $attrs, $ctrl, $transclude) {
                     $scope.myMethod = function() {
                         ...
                     }
                     $scope.myProperty = 'example';
                }
            };
        }
);

In my template I have:

<div>
    <div transclude-in-scope>
        <button type="button" ng-click="myMethod()">Go</button>
    </div>
    <div>
          Some default content
    </div>
</div>

I would like to be able to replace the button for another element but still have access to the isolated scope. I figured I can do it this way, in the link function:

                    $transclude($scope, function ($clone, $scope) {
                        if ($clone.length) {
                            $element.find('[transclude-in-scope]').replaceWith($clone);
                        }
                    });

Then I can use it like so:

<div my-directive>
    <button type="button" class="some-specific-class" ng-click="myMethod()">Please click</button>
</div>

It's basically like using ng-controller but with a default template. Considering the new transclude-slot functionality I think it would be very useful to be able to have a possibility to tell a directive that I want to transclude in the isolated scope. This way I can change some of the elements on the template, without having to ovveride the whole thing.

Do you think this is something worth putting in Angular? I'd be happy to submit a PR.

@gkalpak
Copy link
Member

gkalpak commented Mar 23, 2016

TBH, I don't think something like this is a good idea. It hurts reusability and separation of concerns by coupling your directive's implementation (e.g. exposing a myMethod() method) with the consumer's data (e.g. using the myMethod() method in the template provided by the consumer of your directive.

You can use lower-level APIs (such as $transclude to achieve what you want, but I don't consider this as something that should be built into the core.

@dmitry-dedukhin
Copy link

dmitry-dedukhin commented Dec 12, 2017

I want to up vote for this feature since sometimes I want such functionality too.
E.g. I have a component that receives $http promise as input and displays server errors.
Inside component I have a transclusion slot and I wants to display retry button in this slot only when server error is not fatal. Fatal error is a 40x error, whereas
50x errors could be temporal and in such case there is a chance to get a success response after retry.

export const ErrorComponent = {
    controller: ErrorController,
    template: ErrorTemplate,
    transclude: {
        footerSlot: '?footer'
    },
    bindings: {
        promise: '<'
    }
};
<error promise="$ctrl.dataLoadingPromise">
  <!-- here comes some markup to display error -->
  <footer>
    <!-- $errorCtrl here is a reference to the error component controller -->
    <button ng-if="$errorCtrl.isFatalError() == false" ng-click="$ctrl.retry()">Retry!<button>
  </footer>
</error>

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants