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
@@ -890,7 +894,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
890
894
891
895
if ( transcludeControllers ) {
892
896
for ( var controllerName in transcludeControllers ) {
893
- $linkNode . data ( '$' + controllerName + 'Controller' , transcludeControllers [ controllerName ] ) ;
897
+ $linkNode . data ( '$' + controllerName + 'Controller' , transcludeControllers [ controllerName ] . instance ) ;
894
898
}
895
899
}
896
900
@@ -1221,6 +1225,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
1221
1225
var terminalPriority = - Number . MAX_VALUE ,
1222
1226
newScopeDirective ,
1223
1227
controllerDirectives = previousCompileContext . controllerDirectives ,
1228
+ controllers ,
1224
1229
newIsolateScopeDirective = previousCompileContext . newIsolateScopeDirective ,
1225
1230
templateDirective = previousCompileContext . templateDirective ,
1226
1231
nonTlbTranscludeDirective = previousCompileContext . nonTlbTranscludeDirective ,
@@ -1458,7 +1463,9 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
1458
1463
value = null ;
1459
1464
1460
1465
if ( elementControllers && retrievalMethod === 'data' ) {
1461
- value = elementControllers [ require ] ;
1466
+ if ( value = elementControllers [ require ] ) {
1467
+ value = value . instance ;
1468
+ }
1462
1469
}
1463
1470
value = value || $element [ retrievalMethod ] ( '$' + require + 'Controller' ) ;
1464
1471
@@ -1491,9 +1498,45 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
1491
1498
}
1492
1499
1493
1500
if ( newIsolateScopeDirective ) {
1494
- var LOCAL_REGEXP = / ^ \s * ( [ @ = & ] ) ( \? ? ) \s * ( \w * ) \s * $ / ;
1495
-
1496
1501
isolateScope = scope . $new ( true ) ;
1502
+ }
1503
+
1504
+ transcludeFn = boundTranscludeFn && controllersBoundTransclude ;
1505
+ if ( controllerDirectives ) {
1506
+ // TODO: merge `controllers` and `elementControllers` into single object.
1507
+ controllers = { } ;
1508
+ elementControllers = { } ;
1509
+ forEach ( controllerDirectives , function ( directive ) {
1510
+ var locals = {
1511
+ $scope : directive === newIsolateScopeDirective || directive . $$isolateScope ? isolateScope : scope ,
1512
+ $element : $element ,
1513
+ $attrs : attrs ,
1514
+ $transclude : transcludeFn
1515
+ } , controllerInstance ;
1516
+
1517
+ controller = directive . controller ;
1518
+ if ( controller == '@' ) {
1519
+ controller = attrs [ directive . name ] ;
1520
+ }
1521
+
1522
+ controllerInstance = $controller ( controller , locals , true , directive . controllerAs ) ;
1523
+
1524
+ // For directives with element transclusion the element is a comment,
1525
+ // but jQuery .data doesn't support attaching data to comment nodes as it's hard to
1526
+ // clean up (http://bugs.jquery.com/ticket/8335).
1527
+ // Instead, we save the controllers for the element in a local hash and attach to .data
1528
+ // later, once we have the actual element.
1529
+ elementControllers [ directive . name ] = controllerInstance ;
1530
+ if ( ! hasElementTranscludeDirective ) {
1531
+ $element . data ( '$' + directive . name + 'Controller' , controllerInstance . instance ) ;
1532
+ }
1533
+
1534
+ controllers [ directive . name ] = controllerInstance ;
1535
+ } ) ;
1536
+ }
1537
+
1538
+ if ( newIsolateScopeDirective ) {
1539
+ var LOCAL_REGEXP = / ^ \s * ( [ @ = & ] ) ( \? ? ) \s * ( \w * ) \s * $ / ;
1497
1540
1498
1541
if ( templateDirective && ( templateDirective === newIsolateScopeDirective ||
1499
1542
templateDirective === newIsolateScopeDirective . $$originalDirective ) ) {
@@ -1502,10 +1545,14 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
1502
1545
$element . data ( '$isolateScopeNoTemplate' , isolateScope ) ;
1503
1546
}
1504
1547
1505
-
1506
-
1507
1548
safeAddClass ( $element , 'ng-isolate-scope' ) ;
1508
1549
1550
+ var isolateScopeController = controllers && controllers [ newIsolateScopeDirective . name ] ;
1551
+ var isolateBindingContext = isolateScope ;
1552
+ if ( isolateScopeController && isolateScopeController . identifier &&
1553
+ newIsolateScopeDirective . bindToController === true ) {
1554
+ isolateBindingContext = isolateScopeController . instance ;
1555
+ }
1509
1556
forEach ( newIsolateScopeDirective . scope , function ( definition , scopeName ) {
1510
1557
var match = definition . match ( LOCAL_REGEXP ) || [ ] ,
1511
1558
attrName = match [ 3 ] || scopeName ,
@@ -1526,7 +1573,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
1526
1573
if ( attrs [ attrName ] ) {
1527
1574
// If the attribute has been provided then we trigger an interpolation to ensure
1528
1575
// the value is there for use in the link fn
1529
- isolateScope [ scopeName ] = $interpolate ( attrs [ attrName ] ) ( scope ) ;
1576
+ isolateBindingContext [ scopeName ] = $interpolate ( attrs [ attrName ] ) ( scope ) ;
1530
1577
}
1531
1578
break ;
1532
1579
@@ -1542,21 +1589,21 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
1542
1589
}
1543
1590
parentSet = parentGet . assign || function ( ) {
1544
1591
// reset the change, or we will throw this exception on every $digest
1545
- lastValue = isolateScope [ scopeName ] = parentGet ( scope ) ;
1592
+ lastValue = isolateBindingContext [ scopeName ] = parentGet ( scope ) ;
1546
1593
throw $compileMinErr ( 'nonassign' ,
1547
1594
"Expression '{0}' used with directive '{1}' is non-assignable!" ,
1548
1595
attrs [ attrName ] , newIsolateScopeDirective . name ) ;
1549
1596
} ;
1550
- lastValue = isolateScope [ scopeName ] = parentGet ( scope ) ;
1597
+ lastValue = isolateBindingContext [ scopeName ] = parentGet ( scope ) ;
1551
1598
var unwatch = scope . $watch ( $parse ( attrs [ attrName ] , function parentValueWatch ( parentValue ) {
1552
- if ( ! compare ( parentValue , isolateScope [ scopeName ] ) ) {
1599
+ if ( ! compare ( parentValue , isolateBindingContext [ scopeName ] ) ) {
1553
1600
// we are out of sync and need to copy
1554
1601
if ( ! compare ( parentValue , lastValue ) ) {
1555
1602
// parent changed and it has precedence
1556
- isolateScope [ scopeName ] = parentValue ;
1603
+ isolateBindingContext [ scopeName ] = parentValue ;
1557
1604
} else {
1558
1605
// if the parent can be assigned then do so
1559
- parentSet ( scope , parentValue = isolateScope [ scopeName ] ) ;
1606
+ parentSet ( scope , parentValue = isolateBindingContext [ scopeName ] ) ;
1560
1607
}
1561
1608
}
1562
1609
return lastValue = parentValue ;
@@ -1566,7 +1613,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
1566
1613
1567
1614
case '&' :
1568
1615
parentGet = $parse ( attrs [ attrName ] ) ;
1569
- isolateScope [ scopeName ] = function ( locals ) {
1616
+ isolateBindingContext [ scopeName ] = function ( locals ) {
1570
1617
return parentGet ( scope , locals ) ;
1571
1618
} ;
1572
1619
break ;
@@ -1579,37 +1626,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
1579
1626
}
1580
1627
} ) ;
1581
1628
}
1582
- transcludeFn = boundTranscludeFn && controllersBoundTransclude ;
1583
- if ( controllerDirectives ) {
1584
- elementControllers = { } ;
1585
- forEach ( controllerDirectives , function ( directive ) {
1586
- var locals = {
1587
- $scope : directive === newIsolateScopeDirective || directive . $$isolateScope ? isolateScope : scope ,
1588
- $element : $element ,
1589
- $attrs : attrs ,
1590
- $transclude : transcludeFn
1591
- } , controllerInstance ;
1592
-
1593
- controller = directive . controller ;
1594
- if ( controller == '@' ) {
1595
- controller = attrs [ directive . name ] ;
1596
- }
1597
-
1598
- controllerInstance = $controller ( controller , locals ) ;
1599
- // For directives with element transclusion the element is a comment,
1600
- // but jQuery .data doesn't support attaching data to comment nodes as it's hard to
1601
- // clean up (http://bugs.jquery.com/ticket/8335).
1602
- // Instead, we save the controllers for the element in a local hash and attach to .data
1603
- // later, once we have the actual element.
1604
- elementControllers [ directive . name ] = controllerInstance ;
1605
- if ( ! hasElementTranscludeDirective ) {
1606
- $element . data ( '$' + directive . name + 'Controller' , controllerInstance ) ;
1607
- }
1608
-
1609
- if ( directive . controllerAs ) {
1610
- locals . $scope [ directive . controllerAs ] = controllerInstance ;
1611
- }
1629
+ if ( controllers ) {
1630
+ forEach ( controllers , function ( controller ) {
1631
+ controller ( ) ;
1612
1632
} ) ;
1633
+ controllers = null ;
1613
1634
}
1614
1635
1615
1636
// PRELINKING
0 commit comments