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
@@ -877,8 +881,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
877
881
? JQLitePrototype . clone . call ( $compileNodes ) // IMPORTANT!!!
878
882
: $compileNodes ;
879
883
880
- forEach ( transcludeControllers , function ( instance , name ) {
881
- $linkNode . data ( '$' + name + 'Controller' , instance ) ;
884
+ forEach ( transcludeControllers , function ( controllerInstance , name ) {
885
+ $linkNode . data ( '$' + name + 'Controller' , controllerInstance . instance ) ;
882
886
} ) ;
883
887
884
888
$linkNode . data ( '$scope' , scope ) ;
@@ -1195,6 +1199,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
1195
1199
var terminalPriority = - Number . MAX_VALUE ,
1196
1200
newScopeDirective ,
1197
1201
controllerDirectives = previousCompileContext . controllerDirectives ,
1202
+ controllers ,
1198
1203
newIsolateScopeDirective = previousCompileContext . newIsolateScopeDirective ,
1199
1204
templateDirective = previousCompileContext . templateDirective ,
1200
1205
nonTlbTranscludeDirective = previousCompileContext . nonTlbTranscludeDirective ,
@@ -1431,7 +1436,9 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
1431
1436
value = null ;
1432
1437
1433
1438
if ( elementControllers && retrievalMethod === 'data' ) {
1434
- value = elementControllers [ require ] ;
1439
+ if ( value = elementControllers [ require ] ) {
1440
+ value = value . instance ;
1441
+ }
1435
1442
}
1436
1443
value = value || $element [ retrievalMethod ] ( '$' + require + 'Controller' ) ;
1437
1444
@@ -1460,9 +1467,43 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
1460
1467
$element = attrs . $$element ;
1461
1468
1462
1469
if ( newIsolateScopeDirective ) {
1463
- var LOCAL_REGEXP = / ^ \s * ( [ @ = & ] ) ( \? ? ) \s * ( \w * ) \s * $ / ;
1464
-
1465
1470
isolateScope = scope . $new ( true ) ;
1471
+ }
1472
+
1473
+ transcludeFn = boundTranscludeFn && controllersBoundTransclude ;
1474
+ if ( controllerDirectives ) {
1475
+ controllers = { } ;
1476
+ forEach ( controllerDirectives , function ( directive ) {
1477
+ var locals = {
1478
+ $scope : directive === newIsolateScopeDirective || directive . $$isolateScope ? isolateScope : scope ,
1479
+ $element : $element ,
1480
+ $attrs : attrs ,
1481
+ $transclude : transcludeFn
1482
+ } , controllerInstance ;
1483
+
1484
+ controller = directive . controller ;
1485
+ if ( controller == '@' ) {
1486
+ controller = attrs [ directive . name ] ;
1487
+ }
1488
+
1489
+ controllerInstance = $controller ( controller , locals , true , directive . controllerAs ) ;
1490
+
1491
+ // For directives with element transclusion the element is a comment,
1492
+ // but jQuery .data doesn't support attaching data to comment nodes as it's hard to
1493
+ // clean up (http://bugs.jquery.com/ticket/8335).
1494
+ // Instead, we save the controllers for the element in a local hash and attach to .data
1495
+ // later, once we have the actual element.
1496
+ elementControllers [ directive . name ] = controllerInstance ;
1497
+ if ( ! hasElementTranscludeDirective ) {
1498
+ $element . data ( '$' + directive . name + 'Controller' , controllerInstance . instance ) ;
1499
+ }
1500
+
1501
+ controllers [ directive . name ] = controllerInstance ;
1502
+ } ) ;
1503
+ }
1504
+
1505
+ if ( newIsolateScopeDirective ) {
1506
+ var LOCAL_REGEXP = / ^ \s * ( [ @ = & ] ) ( \? ? ) \s * ( \w * ) \s * $ / ;
1466
1507
1467
1508
if ( templateDirective && ( templateDirective === newIsolateScopeDirective ||
1468
1509
templateDirective === newIsolateScopeDirective . $$originalDirective ) ) {
@@ -1475,27 +1516,35 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
1475
1516
1476
1517
safeAddClass ( $element , 'ng-isolate-scope' ) ;
1477
1518
1519
+ var isolateScopeController = controllers && controllers [ newIsolateScopeDirective . name ] ;
1520
+ var isolateBindingsContext = isolateScope ;
1521
+ if ( isolateScopeController && isolateScopeController . identifier &&
1522
+ newIsolateScopeDirective . bindToController === true ) {
1523
+ isolateBindingsContext = isolateScopeController . instance ;
1524
+ }
1478
1525
forEach ( newIsolateScopeDirective . scope , function ( definition , scopeName ) {
1479
1526
var match = definition . match ( LOCAL_REGEXP ) || [ ] ,
1480
- attrName = match [ 3 ] || scopeName ,
1527
+ attrName ,
1481
1528
optional = ( match [ 2 ] == '?' ) ,
1482
1529
mode = match [ 1 ] , // @, =, or &
1483
1530
lastValue ,
1484
1531
parentGet , parentSet , compare ;
1485
1532
1533
+ attrName = match [ 3 ] || scopeName ;
1534
+
1486
1535
isolateScope . $$isolateBindings [ scopeName ] = mode + attrName ;
1487
1536
1488
1537
switch ( mode ) {
1489
1538
1490
1539
case '@' :
1491
1540
attrs . $observe ( attrName , function ( value ) {
1492
- isolateScope [ scopeName ] = value ;
1541
+ isolateBindingsContext [ scopeName ] = value ;
1493
1542
} ) ;
1494
1543
attrs . $$observers [ attrName ] . $$scope = scope ;
1495
1544
if ( attrs [ attrName ] ) {
1496
1545
// If the attribute has been provided then we trigger an interpolation to ensure
1497
1546
// the value is there for use in the link fn
1498
- isolateScope [ scopeName ] = $interpolate ( attrs [ attrName ] ) ( scope ) ;
1547
+ isolateBindingsContext [ scopeName ] = $interpolate ( attrs [ attrName ] ) ( scope ) ;
1499
1548
}
1500
1549
break ;
1501
1550
@@ -1511,21 +1560,21 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
1511
1560
}
1512
1561
parentSet = parentGet . assign || function ( ) {
1513
1562
// reset the change, or we will throw this exception on every $digest
1514
- lastValue = isolateScope [ scopeName ] = parentGet ( scope ) ;
1563
+ lastValue = isolateBindingsContext [ scopeName ] = parentGet ( scope ) ;
1515
1564
throw $compileMinErr ( 'nonassign' ,
1516
1565
"Expression '{0}' used with directive '{1}' is non-assignable!" ,
1517
1566
attrs [ attrName ] , newIsolateScopeDirective . name ) ;
1518
1567
} ;
1519
- lastValue = isolateScope [ scopeName ] = parentGet ( scope ) ;
1568
+ lastValue = isolateBindingsContext [ scopeName ] = parentGet ( scope ) ;
1520
1569
var unwatch = scope . $watch ( $parse ( attrs [ attrName ] , function parentValueWatch ( parentValue ) {
1521
- if ( ! compare ( parentValue , isolateScope [ scopeName ] ) ) {
1570
+ if ( ! compare ( parentValue , isolateBindingsContext [ scopeName ] ) ) {
1522
1571
// we are out of sync and need to copy
1523
1572
if ( ! compare ( parentValue , lastValue ) ) {
1524
1573
// parent changed and it has precedence
1525
- isolateScope [ scopeName ] = parentValue ;
1574
+ isolateBindingsContext [ scopeName ] = parentValue ;
1526
1575
} else {
1527
1576
// if the parent can be assigned then do so
1528
- parentSet ( scope , parentValue = isolateScope [ scopeName ] ) ;
1577
+ parentSet ( scope , parentValue = isolateBindingsContext [ scopeName ] ) ;
1529
1578
}
1530
1579
}
1531
1580
return lastValue = parentValue ;
@@ -1535,7 +1584,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
1535
1584
1536
1585
case '&' :
1537
1586
parentGet = $parse ( attrs [ attrName ] ) ;
1538
- isolateScope [ scopeName ] = function ( locals ) {
1587
+ isolateBindingsContext [ scopeName ] = function ( locals ) {
1539
1588
return parentGet ( scope , locals ) ;
1540
1589
} ;
1541
1590
break ;
@@ -1548,36 +1597,12 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
1548
1597
}
1549
1598
} ) ;
1550
1599
}
1551
- transcludeFn = boundTranscludeFn && controllersBoundTransclude ;
1552
- if ( controllerDirectives ) {
1553
- forEach ( controllerDirectives , function ( directive ) {
1554
- var locals = {
1555
- $scope : directive === newIsolateScopeDirective || directive . $$isolateScope ? isolateScope : scope ,
1556
- $element : $element ,
1557
- $attrs : attrs ,
1558
- $transclude : transcludeFn
1559
- } , controllerInstance ;
1560
1600
1561
- controller = directive . controller ;
1562
- if ( controller == '@' ) {
1563
- controller = attrs [ directive . name ] ;
1564
- }
1565
-
1566
- controllerInstance = $controller ( controller , locals ) ;
1567
- // For directives with element transclusion the element is a comment,
1568
- // but jQuery .data doesn't support attaching data to comment nodes as it's hard to
1569
- // clean up (http://bugs.jquery.com/ticket/8335).
1570
- // Instead, we save the controllers for the element in a local hash and attach to .data
1571
- // later, once we have the actual element.
1572
- elementControllers [ directive . name ] = controllerInstance ;
1573
- if ( ! hasElementTranscludeDirective ) {
1574
- $element . data ( '$' + directive . name + 'Controller' , controllerInstance ) ;
1575
- }
1576
-
1577
- if ( directive . controllerAs ) {
1578
- locals . $scope [ directive . controllerAs ] = controllerInstance ;
1579
- }
1601
+ if ( controllers ) {
1602
+ forEach ( controllers , function ( controller , key ) {
1603
+ controller ( ) ;
1580
1604
} ) ;
1605
+ controllers = null ;
1581
1606
}
1582
1607
1583
1608
// PRELINKING
0 commit comments