Richer transclusion for AngularJS; see http://zachsnow.com/blog/2013/angularjs-multi-transclusion/ or check out this demo.
This is still somewhat of an experiment.
- AngularJS (duh).
-
Load
multi-transclude.js. -
Add
multi-transcludeas a dependency to your angular module.
angular.module('yourModule', [
// ... other dependencies ...
'multi-transclude'
]);- Use
ng-multi-transclude,ng-multi-template, andng-multi-transclude-controllerin your templates.
Transclusion in AngularJS allows you to write a directive that is parameterized by a block of HTML. Multi-transclusion allows you to write directives that are parameters by multiple blocks of HTML.
Consider an example: a fancy cancel button that has a
text-replaced icon and a title that should be styled specially.
In the former case, we might have a directive ng-button that populates
the following template:
<button class="ng-button">
<i class="cancel-icon"></i>
<span ng-transclude class="title"></span>
</button>And use it thus:
<div ng-button>
Are you <b>sure</b> you want to delete the thing?
</div>Which would generate:
<button class="ng-button">
<i class="cancel-icon"></i>
<span>
Are you <b>sure</b> you want to delete the thing?
</span>
</button>With multi-transclusion, you can write directives whose templates
have several "holes" that you can populate individually, by name.
Let's expand our example to a directive ng-multi-button, that
has both a title and a hint, both of which should be allowed
to be arbitrary templates:
<button class="ng-multi-button">
<div>
<i class="cancel-icon"></i>
<span ng-multi-transclude="title" class="title"></span>
</div>
<div>
<i class="hint-icon"></i>
<span ng-multi-transclude="hint" class="hint"></span>
</div>
</button>Now we can populate each block independently, reusing the structure
in the directive's template instead of forcing each use
of ng-button to include its own hint.
<div ng-multi-button>
<span name="title">
Are you <b>sure</b> you want to delete the thing?
</span>
<span name="hint">
When you delete the thing it's gone <i>forever</i>,
so be extra careful!
</span>
</div>The multi-transclude library includes 3 directives: the eponymous
ng-multi-transclude, along with ng-multi-template and ng-multi-transclude-controller.
The simplest case is when you'd like to define a template (either inline
in a directive definition, via template, or in a <script /> tag via templateUrl)
that allows multi-transclusion. Simply define your template thus, naming
various multi-transclude blocks.
<script type="text/ng-template" id="some-template">
<h1>Some template</h1>
<div class="main-content" ng-multi-transclude="some-block"></div>
<div class="some-chrome">
<div class="secondary-content" ng-multi-transclude="another-block"></div>
</div>
</script>When you want to instantiate your template, use the ng-multi-template directive,
populating the named blocks. Note that you must declare your block parameters
as immediate children of the ng-multi-template usage.
<div ng-multi-template="some-template">
<div name="some-block">...</div>
<div name="another-block">...</div>
</div>Sometimes you'd like to define your own directive that, along with a multi-transclusion
template, has a fancy link function. To do that you need to use ng-multi-transclude-controller
to "wrap" all instances of ng-multi-transclude in your template:
app.directive('ngAnotherDirective', function(){
return {
templateUrl: 'another-template',
link: function(scope, element, attrs){
// Some fancy logic.
}
}
}); <script type="text/ng-template" id="another-template">
<h1>Another template</h1>
<div ng-multi-transclude-controller>
<div class="main-content" ng-multi-transclude="some-block"></div>
<div class="some-chrome">
<div class="secondary-content" ng-multi-transclude="another-block"></div>
</div>
</div>
</script>Then you can use your new custom directive as follows:
<div ng-another-directive>
<div name="some-block">...</div>
<div name="another-block">...</div>
</div>You can provide default block content in your template, too; this content will be used if there is no matching block passed to the directive:
<script type="text/ng-template" id="some-template">
<div ng-multi-transclude="required-block"></div>
<div ng-multi-transclude="optional-block">
And here's some default content.
</div>
</script>To see something like this in action, check out this demo.