@@ -3515,6 +3515,202 @@ describe('$compile', function() {
3515
3515
} ) ;
3516
3516
} ) ;
3517
3517
3518
+ describe ( 'controller lifecycle hooks' , function ( ) {
3519
+
3520
+ describe ( '$onInit' , function ( ) {
3521
+
3522
+ it ( 'should call `$onInit`, if provided, after all the controllers on the element have been initialized' , function ( ) {
3523
+
3524
+ function check ( ) {
3525
+ /*jshint validthis:true */
3526
+ expect ( this . element . controller ( 'd1' ) . id ) . toEqual ( 1 ) ;
3527
+ expect ( this . element . controller ( 'd2' ) . id ) . toEqual ( 2 ) ;
3528
+ }
3529
+
3530
+ function Controller1 ( $element ) { this . id = 1 ; this . element = $element ; }
3531
+ Controller1 . prototype . $onInit = jasmine . createSpy ( '$onInit' ) . and . callFake ( check ) ;
3532
+
3533
+ function Controller2 ( $element ) { this . id = 2 ; this . element = $element ; }
3534
+ Controller2 . prototype . $onInit = jasmine . createSpy ( '$onInit' ) . and . callFake ( check ) ;
3535
+
3536
+ angular . module ( 'my' , [ ] )
3537
+ . directive ( 'd1' , valueFn ( { controller : Controller1 } ) )
3538
+ . directive ( 'd2' , valueFn ( { controller : Controller2 } ) ) ;
3539
+
3540
+ module ( 'my' ) ;
3541
+ inject ( function ( $compile , $rootScope ) {
3542
+ element = $compile ( '<div d1 d2></div>' ) ( $rootScope ) ;
3543
+ expect ( Controller1 . prototype . $onInit ) . toHaveBeenCalledOnce ( ) ;
3544
+ expect ( Controller2 . prototype . $onInit ) . toHaveBeenCalledOnce ( ) ;
3545
+ } ) ;
3546
+ } ) ;
3547
+ } ) ;
3548
+
3549
+
3550
+ describe ( '$onDestroy' , function ( ) {
3551
+
3552
+ it ( 'should call `$onDestroy`, if provided, on the controller when its scope is destroyed' , function ( ) {
3553
+
3554
+ function TestController ( ) { this . count = 0 ; }
3555
+ TestController . prototype . $onDestroy = function ( ) { this . count ++ ; } ;
3556
+
3557
+ angular . module ( 'my' , [ ] )
3558
+ . directive ( 'd1' , valueFn ( { scope : true , controller : TestController } ) )
3559
+ . directive ( 'd2' , valueFn ( { scope : { } , controller : TestController } ) )
3560
+ . directive ( 'd3' , valueFn ( { controller : TestController } ) ) ;
3561
+
3562
+ module ( 'my' ) ;
3563
+ inject ( function ( $compile , $rootScope ) {
3564
+
3565
+ element = $compile ( '<div><d1 ng-if="show[0]"></d1><d2 ng-if="show[1]"></d2><div ng-if="show[2]"><d3></d3></div></div>' ) ( $rootScope ) ;
3566
+
3567
+ $rootScope . $apply ( 'show = [true, true, true]' ) ;
3568
+ var d1Controller = element . find ( 'd1' ) . controller ( 'd1' ) ;
3569
+ var d2Controller = element . find ( 'd2' ) . controller ( 'd2' ) ;
3570
+ var d3Controller = element . find ( 'd3' ) . controller ( 'd3' ) ;
3571
+
3572
+ expect ( [ d1Controller . count , d2Controller . count , d3Controller . count ] ) . toEqual ( [ 0 , 0 , 0 ] ) ;
3573
+ $rootScope . $apply ( 'show = [false, true, true]' ) ;
3574
+ expect ( [ d1Controller . count , d2Controller . count , d3Controller . count ] ) . toEqual ( [ 1 , 0 , 0 ] ) ;
3575
+ $rootScope . $apply ( 'show = [false, false, true]' ) ;
3576
+ expect ( [ d1Controller . count , d2Controller . count , d3Controller . count ] ) . toEqual ( [ 1 , 1 , 0 ] ) ;
3577
+ $rootScope . $apply ( 'show = [false, false, false]' ) ;
3578
+ expect ( [ d1Controller . count , d2Controller . count , d3Controller . count ] ) . toEqual ( [ 1 , 1 , 1 ] ) ;
3579
+ } ) ;
3580
+ } ) ;
3581
+
3582
+
3583
+ it ( 'should call `$onDestroy` top-down (the same as `scope.$broadcast`)' , function ( ) {
3584
+ var log = [ ] ;
3585
+ function ParentController ( ) { log . push ( 'parent created' ) ; }
3586
+ ParentController . prototype . $onDestroy = function ( ) { log . push ( 'parent destroyed' ) ; } ;
3587
+ function ChildController ( ) { log . push ( 'child created' ) ; }
3588
+ ChildController . prototype . $onDestroy = function ( ) { log . push ( 'child destroyed' ) ; } ;
3589
+ function GrandChildController ( ) { log . push ( 'grand child created' ) ; }
3590
+ GrandChildController . prototype . $onDestroy = function ( ) { log . push ( 'grand child destroyed' ) ; } ;
3591
+
3592
+ angular . module ( 'my' , [ ] )
3593
+ . directive ( 'parent' , valueFn ( { scope : true , controller : ParentController } ) )
3594
+ . directive ( 'child' , valueFn ( { scope : true , controller : ChildController } ) )
3595
+ . directive ( 'grandChild' , valueFn ( { scope : true , controller : GrandChildController } ) ) ;
3596
+
3597
+ module ( 'my' ) ;
3598
+ inject ( function ( $compile , $rootScope ) {
3599
+
3600
+ element = $compile ( '<parent ng-if="show"><child><grand-child></grand-child></child></parent>' ) ( $rootScope ) ;
3601
+ $rootScope . $apply ( 'show = true' ) ;
3602
+ expect ( log ) . toEqual ( [ 'parent created' , 'child created' , 'grand child created' ] ) ;
3603
+ log = [ ] ;
3604
+ $rootScope . $apply ( 'show = false' ) ;
3605
+ expect ( log ) . toEqual ( [ 'parent destroyed' , 'child destroyed' , 'grand child destroyed' ] ) ;
3606
+ } ) ;
3607
+ } ) ;
3608
+ } ) ;
3609
+
3610
+
3611
+ describe ( '$afterViewInit' , function ( ) {
3612
+
3613
+ it ( 'should call `$afterViewInit`, if provided, after the element has completed linking (i.e. post-link)' , function ( ) {
3614
+
3615
+ var log = [ ] ;
3616
+
3617
+ function Controller1 ( ) { }
3618
+ Controller1 . prototype . $afterViewInit = function ( ) { log . push ( 'd1 view init' ) ; } ;
3619
+
3620
+ function Controller2 ( ) { }
3621
+ Controller2 . prototype . $afterViewInit = function ( ) { log . push ( 'd2 view init' ) ; } ;
3622
+
3623
+ angular . module ( 'my' , [ ] )
3624
+ . directive ( 'd1' , valueFn ( {
3625
+ controller : Controller1 ,
3626
+ link : { pre : function ( s , e ) { log . push ( 'd1 pre: ' + e . text ( ) ) ; } , post : function ( s , e ) { log . push ( 'd1 post: ' + e . text ( ) ) ; } } ,
3627
+ template : '<d2></d2>'
3628
+ } ) )
3629
+ . directive ( 'd2' , valueFn ( {
3630
+ controller : Controller2 ,
3631
+ link : { pre : function ( s , e ) { log . push ( 'd2 pre: ' + e . text ( ) ) ; } , post : function ( s , e ) { log . push ( 'd2 post: ' + e . text ( ) ) ; } } ,
3632
+ template : 'loaded'
3633
+ } ) ) ;
3634
+
3635
+ module ( 'my' ) ;
3636
+ inject ( function ( $compile , $rootScope ) {
3637
+ element = $compile ( '<d1></d1>' ) ( $rootScope ) ;
3638
+ expect ( log ) . toEqual ( [
3639
+ 'd1 pre: loaded' ,
3640
+ 'd2 pre: loaded' ,
3641
+ 'd2 post: loaded' ,
3642
+ 'd2 view init' ,
3643
+ 'd1 post: loaded' ,
3644
+ 'd1 view init'
3645
+ ] ) ;
3646
+ } ) ;
3647
+ } ) ;
3648
+ } ) ;
3649
+
3650
+
3651
+ describe ( '$onChanges' , function ( ) {
3652
+ it ( 'should call `$onChanges`, if provided, when a one-way (`<`) binding is updated' , function ( ) {
3653
+ var log = [ ] ;
3654
+ function TestController ( ) { }
3655
+ TestController . prototype . $onChanges = function ( change ) { log . push ( change ) ; } ;
3656
+
3657
+ angular . module ( 'my' , [ ] )
3658
+ . component ( 'c1' , {
3659
+ controller : TestController ,
3660
+ bindings : { 'prop1' : '<' , 'prop2' : '<' , 'other' : '=' , 'attr' : '@' }
3661
+ } ) ;
3662
+
3663
+ module ( 'my' ) ;
3664
+ inject ( function ( $compile , $rootScope ) {
3665
+ // Setup a watch to indicate some complicated updated logic
3666
+ $rootScope . $watch ( 'val' , function ( val , oldVal ) { $rootScope . val2 = val * 2 ; } ) ;
3667
+ // Setup the directive with two bindings
3668
+ element = $compile ( '<c1 prop1="val" prop2="val2" other="val3" attr="{{val4}}"></c1>' ) ( $rootScope ) ;
3669
+
3670
+ // There should be no changes initially
3671
+ expect ( log ) . toEqual ( [ ] ) ;
3672
+
3673
+ // Update val to trigger the onChanges
3674
+ $rootScope . $apply ( 'val = 42' ) ;
3675
+ // Now we should have a single changes entry in the log
3676
+ expect ( log ) . toEqual ( [
3677
+ {
3678
+ prop1 : { previousValue : undefined , currentValue : 42 } ,
3679
+ prop2 : { previousValue : undefined , currentValue : 84 }
3680
+ }
3681
+ ] ) ;
3682
+
3683
+ // Clear the log
3684
+ log = [ ] ;
3685
+
3686
+ // Update val to trigger the onChanges
3687
+ $rootScope . $apply ( 'val = 17' ) ;
3688
+ // Now we should have a single changes entry in the log
3689
+ expect ( log ) . toEqual ( [
3690
+ {
3691
+ prop1 : { previousValue : 42 , currentValue : 17 } ,
3692
+ prop2 : { previousValue : 84 , currentValue : 34 }
3693
+ }
3694
+ ] ) ;
3695
+
3696
+ // Clear the log
3697
+ log = [ ] ;
3698
+
3699
+ // Update val3 to trigger the "other" two-way binding
3700
+ $rootScope . $apply ( 'val3 = 63' ) ;
3701
+ // onChanges should not have been called
3702
+ expect ( log ) . toEqual ( [ ] ) ;
3703
+
3704
+ // Update val4 to trigger the "attr" interpolation binding
3705
+ $rootScope . $apply ( 'val3 = 22' ) ;
3706
+ // onChanges should not have been called
3707
+ expect ( log ) . toEqual ( [ ] ) ;
3708
+
3709
+ } ) ;
3710
+ } ) ;
3711
+ } ) ;
3712
+ } ) ;
3713
+
3518
3714
3519
3715
describe ( 'isolated locals' , function ( ) {
3520
3716
var componentScope , regularScope ;
@@ -5324,32 +5520,6 @@ describe('$compile', function() {
5324
5520
} ) ;
5325
5521
} ) ;
5326
5522
5327
- it ( 'should call `controller.$onInit`, if provided after all the controllers have been constructed' , function ( ) {
5328
-
5329
- function check ( ) {
5330
- /*jshint validthis:true */
5331
- expect ( this . element . controller ( 'd1' ) . id ) . toEqual ( 1 ) ;
5332
- expect ( this . element . controller ( 'd2' ) . id ) . toEqual ( 2 ) ;
5333
- }
5334
-
5335
- function Controller1 ( $element ) { this . id = 1 ; this . element = $element ; }
5336
- Controller1 . prototype . $onInit = jasmine . createSpy ( '$onInit' ) . and . callFake ( check ) ;
5337
-
5338
- function Controller2 ( $element ) { this . id = 2 ; this . element = $element ; }
5339
- Controller2 . prototype . $onInit = jasmine . createSpy ( '$onInit' ) . and . callFake ( check ) ;
5340
-
5341
- angular . module ( 'my' , [ ] )
5342
- . directive ( 'd1' , valueFn ( { controller : Controller1 } ) )
5343
- . directive ( 'd2' , valueFn ( { controller : Controller2 } ) ) ;
5344
-
5345
- module ( 'my' ) ;
5346
- inject ( function ( $compile , $rootScope ) {
5347
- element = $compile ( '<div d1 d2></div>' ) ( $rootScope ) ;
5348
- expect ( Controller1 . prototype . $onInit ) . toHaveBeenCalledOnce ( ) ;
5349
- expect ( Controller2 . prototype . $onInit ) . toHaveBeenCalledOnce ( ) ;
5350
- } ) ;
5351
- } ) ;
5352
-
5353
5523
describe ( 'should not overwrite @-bound property each digest when not present' , function ( ) {
5354
5524
it ( 'when creating new scope' , function ( ) {
5355
5525
module ( function ( $compileProvider ) {
0 commit comments