Skip to content
This repository has been archived by the owner on Sep 5, 2024. It is now read-only.

Commit

Permalink
feat(select): add ngMultiple support to select
Browse files Browse the repository at this point in the history
closes #1845
  • Loading branch information
rschmukler committed Mar 25, 2015
1 parent ddf1198 commit 9956f62
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 36 deletions.
2 changes: 0 additions & 2 deletions src/components/select/demoBasicUsage/script.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
angular.module('selectDemoBasic', ['ngMaterial'])
.controller('AppCtrl', function($scope) {
$scope.neighborhoods = ['Chelsea', 'Financial District', 'Midtown', 'West Village', 'Williamsburg'];
$scope.neighborhoods2 = ['Chelsea', 'Financial District', 'Lower Manhattan', 'Midtown', 'Soho', 'Upper Manhattan', 'West Village', 'Williamsburg' ];
});
101 changes: 67 additions & 34 deletions src/components/select/select.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
- [ ] ng-model="foo" ng-model-options="{ trackBy: '$value.id' }" for objects
- [ ] mdOption with value
- [ ] Usage with input inside
- [ ] Usage with md-multiple
### TODO - POST RC1 ###
- [ ] Abstract placement logic in $mdSelect service to $mdMenu service
Expand Down Expand Up @@ -134,7 +133,6 @@ function SelectDirective($mdSelect, $mdUtil, $mdTheming, $interpolate, $compile,
createSelect();

var originalRender = ngModel.$render;

ngModel.$render = function() {
originalRender();
syncLabelText();
Expand All @@ -161,6 +159,31 @@ function SelectDirective($mdSelect, $mdUtil, $mdTheming, $interpolate, $compile,
}
}

var deregisterWatcher;
attr.$observe('ngMultiple', function(val) {
if (deregisterWatcher) deregisterWatcher();
var parser = $parse(val);
deregisterWatcher = scope.$watch(function() { return parser(scope); }, function(multiple, prevVal) {
if (multiple === undefined && prevVal === undefined) return; // assume compiler did a good job
if (multiple) {
element.attr('multiple', 'multiple');
} else {
element.removeAttr('multiple');
}
if (selectContainer) {
var selectMenuCtrl = selectContainer.find('md-select-menu').controller('mdSelectMenu');
selectMenuCtrl.setMultiple(multiple);
originalRender = ngModel.$render;
ngModel.$render = function() {
originalRender();
syncLabelText();
};
selectMenuCtrl.refreshViewValue();
ngModel.$render();
}
});
});

attr.$observe('disabled', function(disabled) {
if (typeof disabled == "string") {
disabled = true;
Expand Down Expand Up @@ -316,6 +339,33 @@ function SelectMenuDirective($parse, $mdUtil, $mdTheming) {
// and values matching every option's controller.
self.options = {};

var deregisterCollectionWatch;
self.setMultiple = function(isMultiple) {
var ngModel = self.ngModel;
self.isMultiple = isMultiple;
if (deregisterCollectionWatch) deregisterCollectionWatch();

if (self.isMultiple) {
ngModel.$validators['md-multiple'] = validateArray;
ngModel.$render = renderMultiple;

// watchCollection on the model because by default ngModel only watches the model's
// reference. This allowed the developer to also push and pop from their array.
$scope.$watchCollection($attrs.ngModel, function(value) {
if (validateArray(value)) renderMultiple(value);
});
} else {
delete ngModel.$validators['md-multiple'];
ngModel.$render = renderSingular;
}

function validateArray(modelValue, viewValue) {
// If a value is truthy but not an array, reject it.
// If value is undefined/falsy, accept that it's an empty array.
return angular.isArray(modelValue || viewValue || []);
}
};


self.init = function(ngModel) {
self.ngModel = ngModel;
Expand All @@ -339,25 +389,7 @@ function SelectMenuDirective($parse, $mdUtil, $mdTheming) {
return value;
};
}

if (self.isMultiple) {
ngModel.$validators['md-multiple'] = validateArray;
ngModel.$render = renderMultiple;

// watchCollection on the model because by default ngModel only watches the model's
// reference. This allowed the developer to also push and pop from their array.
$scope.$watchCollection($attrs.ngModel, function(value) {
if (validateArray(value)) renderMultiple(value);
});
} else {
ngModel.$render = renderSingular;
}

function validateArray(modelValue, viewValue) {
// If a value is truthy but not an array, reject it.
// If value is undefined/falsy, accept that it's an empty array.
return angular.isArray(modelValue || viewValue || []);
}
self.setMultiple(self.isMultiple);
};

self.selectedLabels = function() {
Expand Down Expand Up @@ -694,19 +726,20 @@ function SelectProvider($$interimElementProvider) {
focusOption('prev');
}

if (!selectCtrl.isMultiple) {
opts.selectEl.on('click', closeMenu);
opts.selectEl.on('keydown', function(e) {
if (e.keyCode == 32 || e.keyCode == 13) {
closeMenu();
}
});
}
function closeMenu() {
opts.restoreFocus = true;
scope.$evalAsync(function() {
$mdSelect.hide(selectCtrl.ngModel.$viewValue);
});
opts.selectEl.on('click', checkCloseMenu);
opts.selectEl.on('keydown', function(e) {
if (e.keyCode == 32 || e.keyCode == 13) {
checkCloseMenu();
}
});

function checkCloseMenu() {
if (!selectCtrl.isMultiple) {
opts.restoreFocus = true;
scope.$evalAsync(function() {
$mdSelect.hide(selectCtrl.ngModel.$viewValue);
});
}
}
}

Expand Down

0 comments on commit 9956f62

Please sign in to comment.