Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular.js: Wrapping elements in a nested transclude

This seems like such a simple thing, but I am just not able to wrap my head around how to do it.

Here is what I want:

<my-buttons>
  <my-button ng-click="doOneThing()">abc</my-button>
  <my-button ng-click="doAnotherThing()">def</my-button>
</my-buttons>

That turns into something like this:

<ul class="u">
  <li class="l"><button ng-click="doOneThing()">abc</button></li>
  <li class="l"><button ng-click="doAnotherThing()">def</button></li>
</ul>

Notice how the ng-click is on the button, inside a wrapping li. However, the normal transclusion will place the ng-click on the li.

My best try is on this fiddle: http://jsfiddle.net/WTv7k/1/ There I have replaced the ng-click with a class, so it is easy to see when it works and not.

Any ideas of how to get this done? If it is really easy, maybe the tabs/pane example on the frontpage could be expanded to include a wrapper around the panes, while still keeping the attributes.

like image 633
Magnar Avatar asked Apr 06 '13 19:04

Magnar


1 Answers

With replace:true the replacement process migrates all of the attributes / classes from the old element (<my-button ...>) to the new one (the root element in the template, <li ...> ). Transclude moves the content of the old element to the specified (ng-transclude) element. I'm not sure if there's a simple way to change which element in the template that will receive the migrated attributes.

To achieve what you want you could probably do some dom manipulation in a custom compile function in the my-button directive. However, I think it'd be a better idea to create a new isolate scope in the my-button directive:

<my-buttons>
  <my-button click-fn="doOneThing()">abc</my-button>
  <my-button click-fn="doAnotherThing()">def</my-button>
</my-buttons>

(notice I've changed ng-click to click-fn)

module.directive('myButtons', function () {
  return {
    restrict:'E',
    transclude:true,
    replace:true,
    template:'<ul class="u" ng-transclude></ul>'
  }
});

module.directive('myButton', function () {
  return {
    scope:{clickFn:'&'},
    restrict:'E',
    transclude:true,
    replace:true,
    template:'<li class="l"><button ng-click="clickFn()" ng-transclude></button></li>'
  }
});

I've also made a working version of your fiddle.

To understand how the isolate scope works (scope:{clickFn:'&'}) I recommend you read the angular guide on directives.

like image 176
joakimbl Avatar answered Dec 13 '22 11:12

joakimbl