337
337
* The contents are compiled and provided to the directive as a **transclusion function**. See the
338
338
* {@link $compile#transclusion Transclusion} section below.
339
339
*
340
- * There are two kinds of transclusion depending upon whether you want to transclude just the contents of the
341
- * directive's element or the entire element:
340
+ * There are three kinds of transclusion depending upon whether you want to transclude just the contents of the
341
+ * directive's element, the entire element or parts of the element:
342
342
*
343
343
* * `true` - transclude the content (i.e. the child nodes) of the directive's element.
344
344
* * `'element'` - transclude the whole of the directive's element including any directives on this
345
345
* element that defined at a lower priority than this directive. When used, the `template`
346
346
* property is ignored.
347
- *
347
+ * * **`{...}` (an object hash):** - map elements of the content onto transclusion "slots" in the template.
348
+ * See {@link ngTransclude} for more information.
348
349
*
349
350
* #### `compile`
350
351
*
@@ -1511,7 +1512,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
1511
1512
// so that they are available inside the `controllersBoundTransclude` function
1512
1513
var boundSlots = boundTranscludeFn . $$slots = createMap ( ) ;
1513
1514
for ( var slotName in transcludeFn . $$slots ) {
1514
- boundSlots [ slotName ] = createBoundTranscludeFn ( scope , transcludeFn . $$slots [ slotName ] , previousBoundTranscludeFn ) ;
1515
+ if ( transcludeFn . $$slots [ slotName ] ) {
1516
+ boundSlots [ slotName ] = createBoundTranscludeFn ( scope , transcludeFn . $$slots [ slotName ] , previousBoundTranscludeFn ) ;
1517
+ } else {
1518
+ boundSlots [ slotName ] = null ;
1519
+ }
1515
1520
}
1516
1521
1517
1522
return boundTranscludeFn ;
@@ -1870,7 +1875,10 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
1870
1875
var optional = ( slotName . charAt ( 0 ) === '?' ) ;
1871
1876
slotName = optional ? slotName . substring ( 1 ) : slotName ;
1872
1877
slotNames [ key ] = slotName ;
1873
- slots [ slotName ] = [ ] ;
1878
+ // We explicitly assign `null` since this implies that a slot was defined but not filled.
1879
+ // Later when calling boundTransclusion functions with a slot name we only error if the
1880
+ // slot is `undefined`
1881
+ slots [ slotName ] = null ;
1874
1882
// filledSlots contains `true` for all slots that are either optional or have been
1875
1883
// filled. This is used to check that we have not missed any required slots
1876
1884
filledSlots [ slotName ] = optional ;
@@ -1881,6 +1889,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
1881
1889
var slotName = slotNames [ directiveNormalize ( nodeName_ ( node ) ) ] ;
1882
1890
if ( slotName ) {
1883
1891
filledSlots [ slotName ] = true ;
1892
+ slots [ slotName ] = slots [ slotName ] || [ ] ;
1884
1893
slots [ slotName ] . push ( node ) ;
1885
1894
} else {
1886
1895
$template . push ( node ) ;
@@ -1894,9 +1903,12 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
1894
1903
}
1895
1904
} ) ;
1896
1905
1897
- forEach ( Object . keys ( slots ) , function ( slotName ) {
1898
- slots [ slotName ] = compilationGenerator ( mightHaveMultipleTransclusionError , slots [ slotName ] , transcludeFn ) ;
1899
- } ) ;
1906
+ for ( var slotName in slots ) {
1907
+ if ( slots [ slotName ] ) {
1908
+ // Only define a transclusion function if the slot was filled
1909
+ slots [ slotName ] = compilationGenerator ( mightHaveMultipleTransclusionError , slots [ slotName ] , transcludeFn ) ;
1910
+ }
1911
+ }
1900
1912
}
1901
1913
1902
1914
$compileNode . empty ( ) ; // clear contents
@@ -2125,6 +2137,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
2125
2137
// is later passed as `parentBoundTranscludeFn` to `publicLinkFn`
2126
2138
transcludeFn = controllersBoundTransclude ;
2127
2139
transcludeFn . $$boundTransclude = boundTranscludeFn ;
2140
+ transcludeFn . $$slots = boundTranscludeFn . $$slots ;
2128
2141
}
2129
2142
2130
2143
if ( controllerDirectives ) {
@@ -2222,13 +2235,15 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
2222
2235
}
2223
2236
if ( slotName ) {
2224
2237
var slotTranscludeFn = boundTranscludeFn . $$slots [ slotName ] ;
2225
- if ( ! slotTranscludeFn ) {
2238
+ if ( slotTranscludeFn ) {
2239
+ return slotTranscludeFn ( scope , cloneAttachFn , transcludeControllers , futureParentElement , scopeToChild ) ;
2240
+ }
2241
+ if ( isUndefined ( slotTranscludeFn ) ) {
2226
2242
throw $compileMinErr ( 'noslot' ,
2227
2243
'No parent directive that requires a transclusion with slot name "{0}". ' +
2228
2244
'Element: {1}' ,
2229
2245
slotName , startingTag ( $element ) ) ;
2230
2246
}
2231
- return slotTranscludeFn ( scope , cloneAttachFn , transcludeControllers , futureParentElement , scopeToChild ) ;
2232
2247
}
2233
2248
return boundTranscludeFn ( scope , cloneAttachFn , transcludeControllers , futureParentElement , scopeToChild ) ;
2234
2249
}
0 commit comments