@@ -412,111 +412,6 @@ describe('ngMessages', function() {
412
412
} ) ) ;
413
413
414
414
415
- it ( 'should not crash or leak memory when the messages are transcluded, the first message is' +
416
- 'visible, and ngMessages is removed by ngIf' , function ( ) {
417
-
418
- module ( function ( $compileProvider ) {
419
- $compileProvider . directive ( 'messageWrap' , function ( ) {
420
- return {
421
- transclude : true ,
422
- scope : {
423
- col : '=col'
424
- } ,
425
- template : '<div ng-messages="col"><ng-transclude></ng-transclude></div>'
426
- } ;
427
- } ) ;
428
- } ) ;
429
-
430
- inject ( function ( $rootScope , $compile ) {
431
-
432
- element = $compile ( '<div><div ng-if="show"><div message-wrap col="col">' +
433
- ' <div ng-message="a">A</div>' +
434
- ' <div ng-message="b">B</div>' +
435
- '</div></div></div>' ) ( $rootScope ) ;
436
-
437
- $rootScope . $apply ( function ( ) {
438
- $rootScope . show = true ;
439
- $rootScope . col = {
440
- a : true ,
441
- b : true
442
- } ;
443
- } ) ;
444
-
445
- expect ( messageChildren ( element ) . length ) . toBe ( 1 ) ;
446
- expect ( trim ( element . text ( ) ) ) . toEqual ( 'A' ) ;
447
-
448
- $rootScope . $apply ( 'show = false' ) ;
449
-
450
- expect ( messageChildren ( element ) . length ) . toBe ( 0 ) ;
451
- } ) ;
452
- } ) ;
453
-
454
-
455
- it ( 'should not crash when the first of two nested messages is removed' , function ( ) {
456
- inject ( function ( $rootScope , $compile ) {
457
-
458
- element = $compile (
459
- '<div ng-messages="col">' +
460
- '<div class="wrapper">' +
461
- '<div ng-message="a">A</div>' +
462
- '<div ng-message="b">B</div>' +
463
- '</div>' +
464
- '</div>'
465
- ) ( $rootScope ) ;
466
-
467
- $rootScope . $apply ( function ( ) {
468
- $rootScope . col = {
469
- a : true ,
470
- b : false
471
- } ;
472
- } ) ;
473
-
474
- expect ( messageChildren ( element ) . length ) . toBe ( 1 ) ;
475
- expect ( trim ( element . text ( ) ) ) . toEqual ( 'A' ) ;
476
-
477
- var nodeA = element [ 0 ] . querySelector ( '[ng-message="a"]' ) ;
478
- nodeA . remove ( ) ;
479
-
480
- expect ( messageChildren ( element ) . length ) . toBe ( 0 ) ;
481
- } ) ;
482
- } ) ;
483
-
484
-
485
- it ( 'should show deeply nested messages correctly after a message has been removed' , function ( ) {
486
- inject ( function ( $rootScope , $compile ) {
487
-
488
- element = $compile (
489
- '<div ng-messages="col" ng-messages-multiple>' +
490
- '<div class="another-wrapper">' +
491
- '<div ng-message="a">A</div>' +
492
- '<div class="wrapper">' +
493
- '<div ng-message="b">B</div>' +
494
- '<div ng-message="c">C</div>' +
495
- '</div>' +
496
- '<div ng-message="d">D</div>' +
497
- '</div>' +
498
- '</div>'
499
- ) ( $rootScope ) ;
500
-
501
- $rootScope . $apply ( function ( ) {
502
- $rootScope . col = {
503
- a : true ,
504
- b : true
505
- } ;
506
- } ) ;
507
-
508
- expect ( messageChildren ( element ) . length ) . toBe ( 2 ) ;
509
- expect ( trim ( element . text ( ) ) ) . toEqual ( 'AB' ) ;
510
-
511
- var nodeB = element [ 0 ] . querySelector ( '[ng-message="b"]' ) ;
512
- nodeB . remove ( ) ;
513
-
514
- expect ( messageChildren ( element ) . length ) . toBe ( 1 ) ;
515
- expect ( trim ( element . text ( ) ) ) . toEqual ( 'A' ) ;
516
- } ) ;
517
- } ) ;
518
-
519
-
520
415
// issue #12856
521
416
it ( 'should only detach the message object that is associated with the message node being removed' ,
522
417
inject ( function ( $rootScope , $compile , $animate ) {
@@ -590,6 +485,126 @@ describe('ngMessages', function() {
590
485
} ) ;
591
486
} ) ;
592
487
488
+ describe ( 'ngMessage nested nested inside elements' , function ( ) {
489
+
490
+ it ( 'should not crash or leak memory when the messages are transcluded, the first message is ' +
491
+ 'visible, and ngMessages is removed by ngIf' , function ( ) {
492
+
493
+ module ( function ( $compileProvider ) {
494
+ $compileProvider . directive ( 'messageWrap' , function ( ) {
495
+ return {
496
+ transclude : true ,
497
+ scope : {
498
+ col : '=col'
499
+ } ,
500
+ template : '<div ng-messages="col"><ng-transclude></ng-transclude></div>'
501
+ } ;
502
+ } ) ;
503
+ } ) ;
504
+
505
+ inject ( function ( $rootScope , $compile ) {
506
+
507
+ element = $compile ( '<div><div ng-if="show"><div message-wrap col="col">' +
508
+ ' <div ng-message="a">A</div>' +
509
+ ' <div ng-message="b">B</div>' +
510
+ '</div></div></div>' ) ( $rootScope ) ;
511
+
512
+ $rootScope . $apply ( function ( ) {
513
+ $rootScope . show = true ;
514
+ $rootScope . col = {
515
+ a : true ,
516
+ b : true
517
+ } ;
518
+ } ) ;
519
+
520
+ expect ( messageChildren ( element ) . length ) . toBe ( 1 ) ;
521
+ expect ( trim ( element . text ( ) ) ) . toEqual ( 'A' ) ;
522
+
523
+ $rootScope . $apply ( 'show = false' ) ;
524
+
525
+ expect ( messageChildren ( element ) . length ) . toBe ( 0 ) ;
526
+ } ) ;
527
+ } ) ;
528
+
529
+
530
+ it ( 'should not crash when the first of two nested messages is removed' , function ( ) {
531
+ inject ( function ( $rootScope , $compile ) {
532
+
533
+ element = $compile (
534
+ '<div ng-messages="col">' +
535
+ '<div class="wrapper">' +
536
+ '<div remove-me ng-message="a">A</div>' +
537
+ '<div ng-message="b">B</div>' +
538
+ '</div>' +
539
+ '</div>'
540
+ ) ( $rootScope ) ;
541
+
542
+ $rootScope . $apply ( function ( ) {
543
+ $rootScope . col = {
544
+ a : true ,
545
+ b : false
546
+ } ;
547
+ } ) ;
548
+
549
+ expect ( messageChildren ( element ) . length ) . toBe ( 1 ) ;
550
+ expect ( trim ( element . text ( ) ) ) . toEqual ( 'A' ) ;
551
+
552
+ var ctrl = element . controller ( 'ngMessages' ) ;
553
+ var deregisterSpy = spyOn ( ctrl , 'deregister' ) . and . callThrough ( ) ;
554
+
555
+ var nodeA = element [ 0 ] . querySelector ( '[ng-message="a"]' ) ;
556
+ jqLite ( nodeA ) . remove ( ) ;
557
+ $rootScope . $digest ( ) ; // The next digest triggers the error
558
+
559
+ // Make sure removing the element triggers the deregistration in ngMessages
560
+ expect ( trim ( deregisterSpy . calls . mostRecent ( ) . args [ 0 ] . nodeValue ) ) . toBe ( 'ngMessage: a' ) ;
561
+ expect ( messageChildren ( element ) . length ) . toBe ( 0 ) ;
562
+ } ) ;
563
+ } ) ;
564
+
565
+
566
+ it ( 'should not crash, but show deeply nested messages correctly after a message ' +
567
+ 'has been removed' , function ( ) {
568
+ inject ( function ( $rootScope , $compile ) {
569
+
570
+ element = $compile (
571
+ '<div ng-messages="col" ng-messages-multiple>' +
572
+ '<div class="another-wrapper">' +
573
+ '<div ng-message="a">A</div>' +
574
+ '<div class="wrapper">' +
575
+ '<div ng-message="b">B</div>' +
576
+ '<div ng-message="c">C</div>' +
577
+ '</div>' +
578
+ '<div ng-message="d">D</div>' +
579
+ '</div>' +
580
+ '</div>'
581
+ ) ( $rootScope ) ;
582
+
583
+ $rootScope . $apply ( function ( ) {
584
+ $rootScope . col = {
585
+ a : true ,
586
+ b : true
587
+ } ;
588
+ } ) ;
589
+
590
+ expect ( messageChildren ( element ) . length ) . toBe ( 2 ) ;
591
+ expect ( trim ( element . text ( ) ) ) . toEqual ( 'AB' ) ;
592
+
593
+ var ctrl = element . controller ( 'ngMessages' ) ;
594
+ var deregisterSpy = spyOn ( ctrl , 'deregister' ) . and . callThrough ( ) ;
595
+
596
+ var nodeB = element [ 0 ] . querySelector ( '[ng-message="b"]' ) ;
597
+ jqLite ( nodeB ) . remove ( ) ;
598
+ $rootScope . $digest ( ) ; // The next digest triggers the error
599
+
600
+ // Make sure removing the element triggers the deregistration in ngMessages
601
+ expect ( trim ( deregisterSpy . calls . mostRecent ( ) . args [ 0 ] . nodeValue ) ) . toBe ( 'ngMessage: b' ) ;
602
+ expect ( messageChildren ( element ) . length ) . toBe ( 1 ) ;
603
+ expect ( trim ( element . text ( ) ) ) . toEqual ( 'A' ) ;
604
+ } ) ;
605
+ } ) ;
606
+ } ) ;
607
+
593
608
describe ( 'when including templates' , function ( ) {
594
609
they ( 'should work with a dynamic collection model which is managed by ngRepeat' ,
595
610
{ '<div ng-messages-include="...">' : '<div ng-messages="item">' +
@@ -901,8 +916,15 @@ describe('ngMessages', function() {
901
916
902
917
expect ( element . text ( ) ) . toBe ( 'B' ) ;
903
918
919
+ var ctrl = element . controller ( 'ngMessages' ) ;
920
+ var deregisterSpy = spyOn ( ctrl , 'deregister' ) . and . callThrough ( ) ;
921
+
904
922
var nodeB = element [ 0 ] . querySelector ( '[ng-message="b"]' ) ;
905
- angular . element ( nodeB ) . remove ( ) ;
923
+ jqLite ( nodeB ) . remove ( ) ;
924
+
925
+ // Make sure removing the element triggers the deregistration in ngMessages
926
+ expect ( trim ( deregisterSpy . calls . mostRecent ( ) . args [ 0 ] . nodeValue ) ) . toBe ( 'ngMessage: b' ) ;
927
+
906
928
$rootScope . $apply ( 'items.a = true' ) ;
907
929
908
930
expect ( element . text ( ) ) . toBe ( 'A' ) ;
0 commit comments