175175 * by calling the `localFn` as `localFn({amount: 22})`.
176176 *
177177 *
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.
178182 *
179183 * #### `controller`
180184 * Controller constructor function. The controller is instantiated before the
@@ -890,7 +894,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
890894
891895 if ( transcludeControllers ) {
892896 for ( var controllerName in transcludeControllers ) {
893- $linkNode . data ( '$' + controllerName + 'Controller' , transcludeControllers [ controllerName ] ) ;
897+ $linkNode . data ( '$' + controllerName + 'Controller' , transcludeControllers [ controllerName ] . instance ) ;
894898 }
895899 }
896900
@@ -1221,6 +1225,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
12211225 var terminalPriority = - Number . MAX_VALUE ,
12221226 newScopeDirective ,
12231227 controllerDirectives = previousCompileContext . controllerDirectives ,
1228+ controllers ,
12241229 newIsolateScopeDirective = previousCompileContext . newIsolateScopeDirective ,
12251230 templateDirective = previousCompileContext . templateDirective ,
12261231 nonTlbTranscludeDirective = previousCompileContext . nonTlbTranscludeDirective ,
@@ -1458,7 +1463,9 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
14581463 value = null ;
14591464
14601465 if ( elementControllers && retrievalMethod === 'data' ) {
1461- value = elementControllers [ require ] ;
1466+ if ( value = elementControllers [ require ] ) {
1467+ value = value . instance ;
1468+ }
14621469 }
14631470 value = value || $element [ retrievalMethod ] ( '$' + require + 'Controller' ) ;
14641471
@@ -1491,9 +1498,45 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
14911498 }
14921499
14931500 if ( newIsolateScopeDirective ) {
1494- var LOCAL_REGEXP = / ^ \s * ( [ @ = & ] ) ( \? ? ) \s * ( \w * ) \s * $ / ;
1495-
14961501 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 * $ / ;
14971540
14981541 if ( templateDirective && ( templateDirective === newIsolateScopeDirective ||
14991542 templateDirective === newIsolateScopeDirective . $$originalDirective ) ) {
@@ -1502,10 +1545,14 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
15021545 $element . data ( '$isolateScopeNoTemplate' , isolateScope ) ;
15031546 }
15041547
1505-
1506-
15071548 safeAddClass ( $element , 'ng-isolate-scope' ) ;
15081549
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+ }
15091556 forEach ( newIsolateScopeDirective . scope , function ( definition , scopeName ) {
15101557 var match = definition . match ( LOCAL_REGEXP ) || [ ] ,
15111558 attrName = match [ 3 ] || scopeName ,
@@ -1526,7 +1573,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
15261573 if ( attrs [ attrName ] ) {
15271574 // If the attribute has been provided then we trigger an interpolation to ensure
15281575 // the value is there for use in the link fn
1529- isolateScope [ scopeName ] = $interpolate ( attrs [ attrName ] ) ( scope ) ;
1576+ isolateBindingContext [ scopeName ] = $interpolate ( attrs [ attrName ] ) ( scope ) ;
15301577 }
15311578 break ;
15321579
@@ -1542,21 +1589,21 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
15421589 }
15431590 parentSet = parentGet . assign || function ( ) {
15441591 // reset the change, or we will throw this exception on every $digest
1545- lastValue = isolateScope [ scopeName ] = parentGet ( scope ) ;
1592+ lastValue = isolateBindingContext [ scopeName ] = parentGet ( scope ) ;
15461593 throw $compileMinErr ( 'nonassign' ,
15471594 "Expression '{0}' used with directive '{1}' is non-assignable!" ,
15481595 attrs [ attrName ] , newIsolateScopeDirective . name ) ;
15491596 } ;
1550- lastValue = isolateScope [ scopeName ] = parentGet ( scope ) ;
1597+ lastValue = isolateBindingContext [ scopeName ] = parentGet ( scope ) ;
15511598 var unwatch = scope . $watch ( $parse ( attrs [ attrName ] , function parentValueWatch ( parentValue ) {
1552- if ( ! compare ( parentValue , isolateScope [ scopeName ] ) ) {
1599+ if ( ! compare ( parentValue , isolateBindingContext [ scopeName ] ) ) {
15531600 // we are out of sync and need to copy
15541601 if ( ! compare ( parentValue , lastValue ) ) {
15551602 // parent changed and it has precedence
1556- isolateScope [ scopeName ] = parentValue ;
1603+ isolateBindingContext [ scopeName ] = parentValue ;
15571604 } else {
15581605 // if the parent can be assigned then do so
1559- parentSet ( scope , parentValue = isolateScope [ scopeName ] ) ;
1606+ parentSet ( scope , parentValue = isolateBindingContext [ scopeName ] ) ;
15601607 }
15611608 }
15621609 return lastValue = parentValue ;
@@ -1566,7 +1613,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
15661613
15671614 case '&' :
15681615 parentGet = $parse ( attrs [ attrName ] ) ;
1569- isolateScope [ scopeName ] = function ( locals ) {
1616+ isolateBindingContext [ scopeName ] = function ( locals ) {
15701617 return parentGet ( scope , locals ) ;
15711618 } ;
15721619 break ;
@@ -1579,37 +1626,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
15791626 }
15801627 } ) ;
15811628 }
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 ( ) ;
16121632 } ) ;
1633+ controllers = null ;
16131634 }
16141635
16151636 // PRELINKING
0 commit comments