@@ -25,9 +25,7 @@ module.exports = {
25
25
26
26
// attach listener
27
27
this . on ( 'change' , function ( ) {
28
- var value = self . multiple
29
- ? getMultiValue ( el )
30
- : el . value
28
+ var value = getValue ( el , self . multiple )
31
29
value = self . number
32
30
? _ . isArray ( value )
33
31
? value . map ( _ . toNumber )
@@ -58,13 +56,16 @@ module.exports = {
58
56
var multi = this . multiple && _ . isArray ( value )
59
57
var options = el . options
60
58
var i = options . length
61
- var option
59
+ var op , val
62
60
while ( i -- ) {
63
- option = options [ i ]
61
+ op = options [ i ]
62
+ val = op . hasOwnProperty ( '_value' )
63
+ ? op . _value
64
+ : op . value
64
65
/* eslint-disable eqeqeq */
65
- option . selected = multi
66
- ? indexOf ( value , option . value ) > - 1
67
- : value == option . value
66
+ op . selected = multi
67
+ ? indexOf ( value , val ) > - 1
68
+ : equals ( value , val )
68
69
/* eslint-enable eqeqeq */
69
70
}
70
71
} ,
@@ -139,10 +140,13 @@ function buildOptions (parent, options) {
139
140
if ( typeof op === 'string' ) {
140
141
el . text = el . value = op
141
142
} else {
142
- if ( op . value != null ) {
143
+ if ( op . value != null && ! _ . isObject ( op . value ) ) {
143
144
el . value = op . value
144
145
}
145
- el . text = op . text || op . value || ''
146
+ // object values gets serialized when set as value,
147
+ // so we store the raw value as a different property
148
+ el . _value = op . value
149
+ el . text = op . text || ''
146
150
if ( op . disabled ) {
147
151
el . disabled = true
148
152
}
@@ -181,29 +185,36 @@ function checkInitialValue () {
181
185
}
182
186
183
187
/**
184
- * Helper to extract a value array for select[multiple]
188
+ * Get select value
185
189
*
186
190
* @param {SelectElement } el
187
- * @return {Array }
191
+ * @param {Boolean } multi
192
+ * @return {Array|* }
188
193
*/
189
194
190
- function getMultiValue ( el ) {
191
- return Array . prototype . filter
192
- . call ( el . options , filterSelected )
193
- . map ( getOptionValue )
194
- }
195
-
196
- function filterSelected ( op ) {
197
- return op . selected
198
- }
199
-
200
- function getOptionValue ( op ) {
201
- return op . value || op . text
195
+ function getValue ( el , multi ) {
196
+ var i = el . options . length
197
+ var res = multi ? [ ] : null
198
+ var op , val
199
+ for ( var i = 0 , l = el . options . length ; i < l ; i ++ ) {
200
+ op = el . options [ i ]
201
+ if ( op . selected ) {
202
+ val = op . hasOwnProperty ( '_value' )
203
+ ? op . _value
204
+ : op . value
205
+ if ( multi ) {
206
+ res . push ( val )
207
+ } else {
208
+ return val
209
+ }
210
+ }
211
+ }
212
+ return res
202
213
}
203
214
204
215
/**
205
216
* Native Array.indexOf uses strict equal, but in this
206
- * case we need to match string/numbers with soft equal.
217
+ * case we need to match string/numbers with custom equal.
207
218
*
208
219
* @param {Array } arr
209
220
* @param {* } val
@@ -212,9 +223,19 @@ function getOptionValue (op) {
212
223
function indexOf ( arr , val ) {
213
224
var i = arr . length
214
225
while ( i -- ) {
215
- /* eslint-disable eqeqeq */
216
- if ( arr [ i ] == val ) return i
217
- /* eslint-enable eqeqeq */
226
+ if ( equals ( arr [ i ] , val ) ) {
227
+ return i
228
+ }
218
229
}
219
230
return - 1
220
231
}
232
+
233
+ /**
234
+ * Check if two values are loosely equal. If two objects
235
+ * have the same shape, they are considered equal too:
236
+ * equals({a: 1}, {a: 1}) => true
237
+ */
238
+
239
+ function equals ( a , b ) {
240
+ return a == b || JSON . stringify ( a ) == JSON . stringify ( b )
241
+ }
0 commit comments