-
Notifications
You must be signed in to change notification settings - Fork 3
/
select-with-options.html
88 lines (83 loc) · 3.94 KB
/
select-with-options.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
<script>
function createOption(parent, label, value, selected) {
var option = document.createElement('option');
option.textContent = label;
option.value = value;
option.autoAdded = true;
if (selected)
option.setAttribute('selected', '');
parent.appendChild(option);
}
new Polymer({
is: 'select-with-options',
extends: 'select',
properties: {
optionsList: { observer: '_optionsListChanged' },
optionValue: { type: String },
optionLabel: { type: String },
keepValueWithNoMatchingOption: Boolean,
value: { // Need to declare this property (thus overriding the native one) or else we don't receive changes from host's bound path
type: String,
observer: '_valueChanged',
notify: true
}
},
ready: function () {
var currentlyInChange = false;
this.addEventListener('change', function () {
// After overriding 'value' property (which is needed, see above), the host's bound path in turn doesn't get updated when user interacts with the control.
// Using `this.set` and firing a 'change' event manually seem to fix it
if (this.selectedIndex >= 0) { // But need to use `selectedIndex`, since the this.value override for some reason does not fetch the value of the underlying native property but shows the unchanged option.
this.set('value', Polymer.dom(this.root).querySelectorAll('option')[this.selectedIndex].value);
try {
if (currentlyInChange)
return;
currentlyInChange = true;
this.fire('change');
}
finally {
currentlyInChange = false;
}
}
}.bind(this));
},
_valueChanged: function () {
this._updateSelectedOption();
},
_optionsListChanged: function(newOptionsList) {
var currentValue = this._getValueString(this.value);
var newValueLabelPairs = newOptionsList.map(function (option) {
return {
value: this._getValueString(this.optionValue ? option[this.optionValue] : option),
label: this.optionLabel ? option[this.optionLabel] : option
};
}.bind(this));
Polymer.dom(this.root).querySelectorAll('option').filter(function (option) { return option.autoAdded; })
.forEach(function (option) {
if (!this.keepValueWithNoMatchingOption && option.selected && !newValueLabelPairs.filter(function(o) { return o.value === currentValue; })[0]) {
this.set('value', '');
this.fire('change'); // Needed so the uses of original <select value="prop::change"> have their prop updated too
}
this.removeChild(option);
}.bind(this));
newValueLabelPairs.forEach(function (option) {
createOption(this, option.label, option.value, currentValue === option.value);
}, this);
},
_updateSelectedOption: function () {
var currentValue = this._getValueString(this.value);
var baseOptions =
Polymer.dom(this.root).querySelectorAll('option')
.forEach(function (option) {
if (this._getValueString(option.getAttribute('value')) == currentValue)
option.selected = true;
}.bind(this));
},
_getValueString: function (val) {
if (val === null || val === undefined)
return '';
else
return val.toString();
}
});
</script>