Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit 4d11d5f

Browse files
committed
fix(select): Fix several issues when moving options between groups
* When an option was moved to a previous group, the group that loose the option would remove the label from the controller * When an entire option group was removed, the options in the group were mot removed from the controller
1 parent 5c43b94 commit 4d11d5f

File tree

2 files changed

+128
-8
lines changed

2 files changed

+128
-8
lines changed

src/ng/directive/select.js

+12-8
Original file line numberDiff line numberDiff line change
@@ -679,18 +679,22 @@ var selectDirective = ['$compile', '$parse', function($compile, $parse) {
679679
updateLabelMap(labelMap, option.label, false);
680680
option.element.remove();
681681
}
682-
forEach(labelMap, function(count, label) {
683-
if (count > 0) {
684-
selectCtrl.addOption(label);
685-
} else if (count < 0) {
686-
selectCtrl.removeOption(label);
687-
}
688-
});
689682
}
690683
// remove any excessive OPTGROUPs from select
691684
while (optionGroupsCache.length > groupIndex) {
692-
optionGroupsCache.pop()[0].element.remove();
685+
optionGroup = optionGroupsCache.pop();
686+
for (index = 1; index < optionGroup.length; ++index) {
687+
updateLabelMap(labelMap, optionGroup[index].label, false);
688+
}
689+
optionGroup[0].element.remove();
693690
}
691+
forEach(labelMap, function(count, label) {
692+
if (count > 0) {
693+
selectCtrl.addOption(label);
694+
} else if (count < 0) {
695+
selectCtrl.removeOption(label);
696+
}
697+
});
694698
}
695699
}
696700
}

test/ng/directive/selectSpec.js

+116
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,122 @@ describe('select', function() {
485485
expect(selectCtrl.hasOption('c3p0')).toBe(true);
486486
expect(selectCtrl.hasOption('r2d2')).toBe(true);
487487
});
488+
it('should keep all the options when changing the model', function() {
489+
compile('<select ng-model="mySelect" ng-options="o for o in [\'A\',\'B\',\'C\']"></select>');
490+
var selectCtrl = element.data().$selectController;
491+
scope.$apply(function() {
492+
scope.mySelect = 'C';
493+
});
494+
expect(selectCtrl.hasOption('C')).toBe(true);
495+
});
496+
it('should be able to detect when elements move from a previous group', function() {
497+
scope.values = [
498+
{name: 'A'},
499+
{name: 'B', group: 'first'},
500+
{name: 'C', group: 'first'},
501+
{name: 'D', group: 'first'},
502+
{name: 'E', group: 'second'}
503+
];
504+
505+
compile('<select ng-model="mySelect" ng-options="item.name group by item.group for item in values"></select>');
506+
var selectCtrl = element.data().$selectController;
507+
508+
scope.$apply(function() {
509+
scope.values[3].group = {name: 'D', group: 'second'};
510+
scope.values.shift();
511+
});
512+
expect(selectCtrl.hasOption('D')).toBe(true);
513+
});
514+
it('should be able to detect when elements move from a following group', function() {
515+
scope.values = [
516+
{name: 'A'},
517+
{name: 'B', group: 'first'},
518+
{name: 'C', group: 'first'},
519+
{name: 'D', group: 'second'},
520+
{name: 'E', group: 'second'}
521+
];
522+
523+
compile('<select ng-model="mySelect" ng-options="item.name group by item.group for item in values"></select>');
524+
var selectCtrl = element.data().$selectController;
525+
526+
scope.$apply(function() {
527+
scope.values[3].group = 'first';
528+
scope.values.shift();
529+
});
530+
expect(selectCtrl.hasOption('D')).toBe(true);
531+
});
532+
it('should be able to detect when an element is replaced with an elements from a previous group', function() {
533+
scope.values = [
534+
{name: 'A'},
535+
{name: 'B', group: 'first'},
536+
{name: 'C', group: 'first'},
537+
{name: 'D', group: 'first'},
538+
{name: 'E', group: 'second'},
539+
{name: 'F', group: 'second'}
540+
];
541+
542+
compile('<select ng-model="mySelect" ng-options="item.name group by item.group for item in values"></select>');
543+
var selectCtrl = element.data().$selectController;
544+
545+
scope.$apply(function() {
546+
scope.values[3].group = 'second';
547+
scope.values.pop();
548+
});
549+
expect(selectCtrl.hasOption('D')).toBe(true);
550+
});
551+
it('should be able to detect when element is replaced with an element from a following group', function() {
552+
scope.values = [
553+
{name: 'A'},
554+
{name: 'B', group: 'first'},
555+
{name: 'C', group: 'first'},
556+
{name: 'D', group: 'second'},
557+
{name: 'E', group: 'second'}
558+
];
559+
560+
compile('<select ng-model="mySelect" ng-options="item.name group by item.group for item in values"></select>');
561+
var selectCtrl = element.data().$selectController;
562+
563+
scope.$apply(function() {
564+
scope.values[3].group = 'first';
565+
scope.values.splice(2, 1);
566+
});
567+
expect(selectCtrl.hasOption('D')).toBe(true);
568+
});
569+
it('should be able to detect when an element is removed', function() {
570+
scope.values = [
571+
{name: 'A'},
572+
{name: 'B', group: 'first'},
573+
{name: 'C', group: 'first'},
574+
{name: 'D', group: 'second'},
575+
{name: 'E', group: 'second'}
576+
];
577+
578+
compile('<select ng-model="mySelect" ng-options="item.name group by item.group for item in values"></select>');
579+
var selectCtrl = element.data().$selectController;
580+
581+
scope.$apply(function() {
582+
scope.values.splice(3, 1);
583+
});
584+
expect(selectCtrl.hasOption('D')).toBe(false);
585+
});
586+
it('should be able to detect when a group is removed', function() {
587+
scope.values = [
588+
{name: 'A'},
589+
{name: 'B', group: 'first'},
590+
{name: 'C', group: 'first'},
591+
{name: 'D', group: 'second'},
592+
{name: 'E', group: 'second'}
593+
];
594+
595+
compile('<select ng-model="mySelect" ng-options="item.name group by item.group for item in values"></select>');
596+
var selectCtrl = element.data().$selectController;
597+
598+
scope.$apply(function() {
599+
scope.values.splice(3, 2);
600+
});
601+
expect(selectCtrl.hasOption('D')).toBe(false);
602+
expect(selectCtrl.hasOption('E')).toBe(false);
603+
});
488604
});
489605
});
490606
});

0 commit comments

Comments
 (0)