Angular1.5でMultipleTransclusionが使えたよ

javascript JavaScript
typescript TypeScript
angular-icon AngularJS

いまさら感ありますが、最近まで全く知らなかった上に日本語情報がほぼ無さそうなのでこれはまとめるしかない。

【参考】
http://blog.thoughtram.io/angular/2015/11/16/multiple-transclusion-and-named-slots.html

そもそもTransclusionってなぁに

Transclusion自体は概念的なものの名前。
AngularJSにおいてはng-transcludeというディレクティブを用いてdirectivecomponentに指定のDOMを含まさせることを意味します。(のはず)

こんなcomponentを定義して

class Container {
    static $inject = ['$scope', '$element']
    constructor(
        private scope: ng.IScope,
        private element: ng.IRootElementService) {
    }
}

angular.module('App').component('container', {
    controller: Container,
    transclude: true,
    bindings: {},
    template:
        `
    <div class="container">
      <div ng-transclude></div>
    </div>
    `
})

こう呼び出すと

<container>
    <div>Hello World!</div>
</container>

こうなる。

<div class="container">
    <div ng-transclude="">
        <div class="ng-scope">Hello World!</div>
    </div>
</div>

とっても便利ではあるのが、1.5以前は単一での指定しかできなかったため幾度か殺意が湧いたりもした。
これがMultiple対応されたということで心踊った。

Multipleになると

名前の通り、複数の指定DOM要素を含ませることができるようになる。

こんなcomponentを定義して

class Container {
    static $inject = ['$scope', '$element']
    constructor(
        private scope: ng.IScope,
        private element: ng.IRootElementService) {
    }
}

app.component('container', {
    controller: Container,
    transclude: {
        content1: 'content1',
        content2: 'content2'
    },
    bindings: {},
    template:
        `
    <div class="container">
      <div ng-transclude="content1"></div>
      <hr/>
      <div ng-transclude="content2"></div>
    </div>
    `
})

こう呼び出すと

<container>
    <content1>Hello</content1>
    <content2>World</content2>
</container>

こうなる。

<container class="ng-isolate-scope">
    <div class="container">
      <div ng-transclude="content1">
          <content1 class="ng-scope">Hello</content1>
      </div>
      <hr>
      <div ng-transclude="content2">
          <content2 class="ng-scope">World</content2>
      </div>
    </div>
</container>

言うまでもなくこの2ヶ所が肝。

transclude: {
    content1: 'content1',
    content2: 'content2'
},
ng-transclude="content1"

注意点

こう呼び出すと

<container>
    <content1>Hello</content1>
</container>

Error: [$compile:reqslot] Required transclusion slot 'content2' was not filled.というスクリプトエラーが発生して描画されない。
もし必須なDOM要素でない場合はこのように?content2のように頭に?を付与する必要がある。注意されたし。

transclude: {
    content1: 'content1',
    content2: '?content2'
},

個人的には<div ng-transclude="content1">のようなdivが勝手に差し込まれさえしなければものすごく嬉しい。
でもとてつもなく可能性の幅が広がった気がした。