175
175
* by calling the `localFn` as `localFn({amount: 22})`.
176
176
*
177
177
*
178
+ * #### `bindToController`
179
+ * When an isolate scope is used for a component (see above), and `controllerAs` is used, `bindToController` will
180
+ * allow a component to have its properties bound to the controller, rather than to scope. When the controller
181
+ * is instantiated, the initial values of the isolate scope bindings are already available.
178
182
*
179
183
* #### `controller`
180
184
* Controller constructor function. The controller is instantiated before the
@@ -981,7 +985,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
981
985
982
986
if ( transcludeControllers ) {
983
987
for ( var controllerName in transcludeControllers ) {
984
- $linkNode . data ( '$' + controllerName + 'Controller' , transcludeControllers [ controllerName ] ) ;
988
+ $linkNode . data ( '$' + controllerName + 'Controller' , transcludeControllers [ controllerName ] . instance ) ;
985
989
}
986
990
}
987
991
@@ -1316,6 +1320,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
1316
1320
var terminalPriority = - Number . MAX_VALUE ,
1317
1321
newScopeDirective ,
1318
1322
controllerDirectives = previousCompileContext . controllerDirectives ,
1323
+ controllers ,
1319
1324
newIsolateScopeDirective = previousCompileContext . newIsolateScopeDirective ,
1320
1325
templateDirective = previousCompileContext . templateDirective ,
1321
1326
nonTlbTranscludeDirective = previousCompileContext . nonTlbTranscludeDirective ,
@@ -1553,7 +1558,9 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
1553
1558
value = null ;
1554
1559
1555
1560
if ( elementControllers && retrievalMethod === 'data' ) {
1556
- value = elementControllers [ require ] ;
1561
+ if ( value = elementControllers [ require ] ) {
1562
+ value = value . instance ;
1563
+ }
1557
1564
}
1558
1565
value = value || $element [ retrievalMethod ] ( '$' + require + 'Controller' ) ;
1559
1566
@@ -1586,14 +1593,56 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
1586
1593
}
1587
1594
1588
1595
if ( newIsolateScopeDirective ) {
1589
- var LOCAL_REGEXP = / ^ \s * ( [ @ = & ] ) ( \? ? ) \s * ( \w * ) \s * $ / ;
1590
-
1591
1596
isolateScope = scope . $new ( true ) ;
1597
+ }
1598
+
1599
+ transcludeFn = boundTranscludeFn && controllersBoundTransclude ;
1600
+ if ( controllerDirectives ) {
1601
+ // TODO: merge `controllers` and `elementControllers` into single object.
1602
+ controllers = { } ;
1603
+ elementControllers = { } ;
1604
+ forEach ( controllerDirectives , function ( directive ) {
1605
+ var locals = {
1606
+ $scope : directive === newIsolateScopeDirective || directive . $$isolateScope ? isolateScope : scope ,
1607
+ $element : $element ,
1608
+ $attrs : attrs ,
1609
+ $transclude : transcludeFn
1610
+ } , controllerInstance ;
1611
+
1612
+ controller = directive . controller ;
1613
+ if ( controller == '@' ) {
1614
+ controller = attrs [ directive . name ] ;
1615
+ }
1616
+
1617
+ controllerInstance = $controller ( controller , locals , true , directive . controllerAs ) ;
1618
+
1619
+ // For directives with element transclusion the element is a comment,
1620
+ // but jQuery .data doesn't support attaching data to comment nodes as it's hard to
1621
+ // clean up (http://bugs.jquery.com/ticket/8335).
1622
+ // Instead, we save the controllers for the element in a local hash and attach to .data
1623
+ // later, once we have the actual element.
1624
+ elementControllers [ directive . name ] = controllerInstance ;
1625
+ if ( ! hasElementTranscludeDirective ) {
1626
+ $element . data ( '$' + directive . name + 'Controller' , controllerInstance . instance ) ;
1627
+ }
1628
+
1629
+ controllers [ directive . name ] = controllerInstance ;
1630
+ } ) ;
1631
+ }
1632
+
1633
+ if ( newIsolateScopeDirective ) {
1634
+ var LOCAL_REGEXP = / ^ \s * ( [ @ = & ] ) ( \? ? ) \s * ( \w * ) \s * $ / ;
1592
1635
1593
1636
compile . $$addScopeInfo ( $element , isolateScope , true , ! ( templateDirective && ( templateDirective === newIsolateScopeDirective ||
1594
1637
templateDirective === newIsolateScopeDirective . $$originalDirective ) ) ) ;
1595
1638
compile . $$addScopeClass ( $element , true ) ;
1596
1639
1640
+ var isolateScopeController = controllers && controllers [ newIsolateScopeDirective . name ] ;
1641
+ var isolateBindingContext = isolateScope ;
1642
+ if ( isolateScopeController && isolateScopeController . identifier &&
1643
+ newIsolateScopeDirective . bindToController === true ) {
1644
+ isolateBindingContext = isolateScopeController . instance ;
1645
+ }
1597
1646
forEach ( newIsolateScopeDirective . scope , function ( definition , scopeName ) {
1598
1647
var match = definition . match ( LOCAL_REGEXP ) || [ ] ,
1599
1648
attrName = match [ 3 ] || scopeName ,
@@ -1614,7 +1663,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
1614
1663
if ( attrs [ attrName ] ) {
1615
1664
// If the attribute has been provided then we trigger an interpolation to ensure
1616
1665
// the value is there for use in the link fn
1617
- isolateScope [ scopeName ] = $interpolate ( attrs [ attrName ] ) ( scope ) ;
1666
+ isolateBindingContext [ scopeName ] = $interpolate ( attrs [ attrName ] ) ( scope ) ;
1618
1667
}
1619
1668
break ;
1620
1669
@@ -1630,21 +1679,21 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
1630
1679
}
1631
1680
parentSet = parentGet . assign || function ( ) {
1632
1681
// reset the change, or we will throw this exception on every $digest
1633
- lastValue = isolateScope [ scopeName ] = parentGet ( scope ) ;
1682
+ lastValue = isolateBindingContext [ scopeName ] = parentGet ( scope ) ;
1634
1683
throw $compileMinErr ( 'nonassign' ,
1635
1684
"Expression '{0}' used with directive '{1}' is non-assignable!" ,
1636
1685
attrs [ attrName ] , newIsolateScopeDirective . name ) ;
1637
1686
} ;
1638
- lastValue = isolateScope [ scopeName ] = parentGet ( scope ) ;
1687
+ lastValue = isolateBindingContext [ scopeName ] = parentGet ( scope ) ;
1639
1688
var unwatch = scope . $watch ( $parse ( attrs [ attrName ] , function parentValueWatch ( parentValue ) {
1640
- if ( ! compare ( parentValue , isolateScope [ scopeName ] ) ) {
1689
+ if ( ! compare ( parentValue , isolateBindingContext [ scopeName ] ) ) {
1641
1690
// we are out of sync and need to copy
1642
1691
if ( ! compare ( parentValue , lastValue ) ) {
1643
1692
// parent changed and it has precedence
1644
- isolateScope [ scopeName ] = parentValue ;
1693
+ isolateBindingContext [ scopeName ] = parentValue ;
1645
1694
} else {
1646
1695
// if the parent can be assigned then do so
1647
- parentSet ( scope , parentValue = isolateScope [ scopeName ] ) ;
1696
+ parentSet ( scope , parentValue = isolateBindingContext [ scopeName ] ) ;
1648
1697
}
1649
1698
}
1650
1699
return lastValue = parentValue ;
@@ -1654,7 +1703,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
1654
1703
1655
1704
case '&' :
1656
1705
parentGet = $parse ( attrs [ attrName ] ) ;
1657
- isolateScope [ scopeName ] = function ( locals ) {
1706
+ isolateBindingContext [ scopeName ] = function ( locals ) {
1658
1707
return parentGet ( scope , locals ) ;
1659
1708
} ;
1660
1709
break ;
@@ -1667,37 +1716,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
1667
1716
}
1668
1717
} ) ;
1669
1718
}
1670
- transcludeFn = boundTranscludeFn && controllersBoundTransclude ;
1671
- if ( controllerDirectives ) {
1672
- elementControllers = { } ;
1673
- forEach ( controllerDirectives , function ( directive ) {
1674
- var locals = {
1675
- $scope : directive === newIsolateScopeDirective || directive . $$isolateScope ? isolateScope : scope ,
1676
- $element : $element ,
1677
- $attrs : attrs ,
1678
- $transclude : transcludeFn
1679
- } , controllerInstance ;
1680
-
1681
- controller = directive . controller ;
1682
- if ( controller == '@' ) {
1683
- controller = attrs [ directive . name ] ;
1684
- }
1685
-
1686
- controllerInstance = $controller ( controller , locals ) ;
1687
- // For directives with element transclusion the element is a comment,
1688
- // but jQuery .data doesn't support attaching data to comment nodes as it's hard to
1689
- // clean up (http://bugs.jquery.com/ticket/8335).
1690
- // Instead, we save the controllers for the element in a local hash and attach to .data
1691
- // later, once we have the actual element.
1692
- elementControllers [ directive . name ] = controllerInstance ;
1693
- if ( ! hasElementTranscludeDirective ) {
1694
- $element . data ( '$' + directive . name + 'Controller' , controllerInstance ) ;
1695
- }
1696
-
1697
- if ( directive . controllerAs ) {
1698
- locals . $scope [ directive . controllerAs ] = controllerInstance ;
1699
- }
1719
+ if ( controllers ) {
1720
+ forEach ( controllers , function ( controller ) {
1721
+ controller ( ) ;
1700
1722
} ) ;
1723
+ controllers = null ;
1701
1724
}
1702
1725
1703
1726
// PRELINKING
0 commit comments