@@ -245,7 +245,7 @@ var NG_OPTIONS_REGEXP = /^\s*([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+group\s+by\s
245
245
// jshint maxlen: 100
246
246
247
247
248
- var ngOptionsDirective = [ '$compile' , '$parse' , function ( $compile , $parse ) {
248
+ var ngOptionsDirective = [ '$compile' , '$document' , '$ parse', function ( $compile , $document , $parse ) {
249
249
250
250
function parseOptionsExpression ( optionsExp , selectElement , scope ) {
251
251
@@ -581,6 +581,8 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
581
581
emptyOption = jqLite ( optionTemplate . cloneNode ( false ) ) ;
582
582
}
583
583
584
+ selectElement . empty ( ) ;
585
+
584
586
// We need to do this here to ensure that the options object is defined
585
587
// when we first hit it in writeNgOptionsValue
586
588
updateOptions ( ) ;
@@ -606,73 +608,35 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
606
608
if ( option . value !== element . value ) element . value = option . selectValue ;
607
609
}
608
610
609
- function addOrReuseElement ( parent , current , type , templateElement ) {
610
- var element ;
611
- // Check whether we can reuse the next element
612
- if ( current && lowercase ( current . nodeName ) === type ) {
613
- // The next element is the right type so reuse it
614
- element = current ;
615
- } else {
616
- // The next element is not the right type so create a new one
617
- element = templateElement . cloneNode ( false ) ;
618
- if ( ! current ) {
619
- // There are no more elements so just append it to the select
620
- parent . appendChild ( element ) ;
621
- } else {
622
- // The next element is not a group so insert the new one
623
- parent . insertBefore ( element , current ) ;
624
- }
625
- }
626
- return element ;
627
- }
628
-
629
-
630
- function removeExcessElements ( current ) {
631
- var next ;
632
- while ( current ) {
633
- next = current . nextSibling ;
634
- jqLiteRemove ( current ) ;
635
- current = next ;
636
- }
637
- }
638
-
611
+ function updateOptions ( ) {
612
+ var previousValue = options && selectCtrl . readValue ( ) ;
639
613
640
- function skipEmptyAndUnknownOptions ( current ) {
641
- var emptyOption_ = emptyOption && emptyOption [ 0 ] ;
642
- var unknownOption_ = unknownOption && unknownOption [ 0 ] ;
643
-
644
- // We cannot rely on the extracted empty option being the same as the compiled empty option,
645
- // because the compiled empty option might have been replaced by a comment because
646
- // it had an "element" transclusion directive on it (such as ngIf)
647
- if ( emptyOption_ || unknownOption_ ) {
648
- while ( current &&
649
- ( current === emptyOption_ ||
650
- current === unknownOption_ ||
651
- current . nodeType === NODE_TYPE_COMMENT ||
652
- ( nodeName_ ( current ) === 'option' && current . value === '' ) ) ) {
653
- current = current . nextSibling ;
614
+ // We must remove all current options, but cannot simply set innerHTML = null
615
+ // since the providedOption might have an ngIf on it that inserts comments, which we must
616
+ // preserve
617
+ // Instead iterate over the current option elements and remove them respectively their
618
+ // optgroup parents
619
+ if ( options ) {
620
+ for ( var i = options . items . length - 1 ; i >= 0 ; i -- ) {
621
+ var option = options . items [ i ] ;
622
+ if ( option . group ) {
623
+ jqLiteRemove ( option . element . parentNode ) ;
624
+ } else {
625
+ jqLiteRemove ( options . items [ i ] . element ) ;
626
+ }
654
627
}
655
628
}
656
- return current ;
657
- }
658
-
659
-
660
- function updateOptions ( ) {
661
-
662
- var previousValue = options && selectCtrl . readValue ( ) ;
663
629
664
630
options = ngOptions . getOptions ( ) ;
665
631
666
632
var groupMap = { } ;
667
- var currentElement = selectElement [ 0 ] . firstChild ;
633
+ var listFragment = $document [ 0 ] . createDocumentFragment ( ) ;
668
634
669
635
// Ensure that the empty option is always there if it was explicitly provided
670
636
if ( providedEmptyOption ) {
671
637
selectElement . prepend ( emptyOption ) ;
672
638
}
673
639
674
- currentElement = skipEmptyAndUnknownOptions ( currentElement ) ;
675
-
676
640
options . items . forEach ( function updateOption ( option ) {
677
641
var group ;
678
642
var groupElement ;
@@ -686,53 +650,35 @@ var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
686
650
687
651
if ( ! group ) {
688
652
689
- // We have not already created this group
690
- groupElement = addOrReuseElement ( selectElement [ 0 ] ,
691
- currentElement ,
692
- 'optgroup' ,
693
- optGroupTemplate ) ;
653
+ groupElement = optGroupTemplate . cloneNode ( false ) ;
654
+ listFragment . appendChild ( groupElement ) ;
655
+
694
656
// Move to the next element
695
- currentElement = groupElement . nextSibling ;
657
+ // currentElement = groupElement.nextSibling;
696
658
697
659
// Update the label on the group element
698
660
groupElement . label = option . group ;
699
661
700
662
// Store it for use later
701
663
group = groupMap [ option . group ] = {
702
- groupElement : groupElement ,
703
- currentOptionElement : groupElement . firstChild
664
+ groupElement : groupElement
704
665
} ;
705
666
706
667
}
707
668
708
- // So now we have a group for this option we add the option to the group
709
- optionElement = addOrReuseElement ( group . groupElement ,
710
- group . currentOptionElement ,
711
- 'option' ,
712
- optionTemplate ) ;
669
+ optionElement = optionTemplate . cloneNode ( false ) ;
670
+ group . groupElement . appendChild ( optionElement ) ;
713
671
updateOptionElement ( option , optionElement ) ;
714
- // Move to the next element
715
- group . currentOptionElement = optionElement . nextSibling ;
716
672
717
673
} else {
718
674
719
- // This option is not in a group
720
- optionElement = addOrReuseElement ( selectElement [ 0 ] ,
721
- currentElement ,
722
- 'option' ,
723
- optionTemplate ) ;
675
+ optionElement = optionTemplate . cloneNode ( false ) ;
676
+ listFragment . appendChild ( optionElement ) ;
724
677
updateOptionElement ( option , optionElement ) ;
725
- // Move to the next element
726
- currentElement = optionElement . nextSibling ;
727
678
}
728
679
} ) ;
729
680
730
-
731
- // Now remove all excess options and group
732
- Object . keys ( groupMap ) . forEach ( function ( key ) {
733
- removeExcessElements ( groupMap [ key ] . currentOptionElement ) ;
734
- } ) ;
735
- removeExcessElements ( currentElement ) ;
681
+ selectElement [ 0 ] . appendChild ( listFragment ) ;
736
682
737
683
ngModelCtrl . $render ( ) ;
738
684
0 commit comments