Last active
August 29, 2015 14:18
-
-
Save cdaringe/2aa1dac555a0a6cb4c79 to your computer and use it in GitHub Desktop.
select-view-diff
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/ampersand-select-view.js b/ampersand-select-view.js | |
index 8b08777..becb863 100644 | |
--- a/ampersand-select-view.js | |
+++ b/ampersand-select-view.js | |
@@ -42,6 +42,7 @@ function SelectView (opts) { | |
this.startingValue = opts.value; | |
this.yieldModel = (opts.yieldModel === false) ? false : true; | |
+ this.eagerValidate = opts.eagerValidate; | |
this.required = opts.required || false; | |
this.validClass = opts.validClass || 'input-valid'; | |
this.invalidClass = opts.invalidClass || 'input-invalid'; | |
@@ -49,9 +50,9 @@ function SelectView (opts) { | |
this.onChange = this.onChange.bind(this); | |
- this.render(); | |
+ this.startingValue = this.setValue(opts.value, this.eagerValidate ? false : true, true); | |
- this.setValue(opts.value, opts.eagerValidate ? false : true); | |
+ this.render(); | |
} | |
SelectView.prototype.render = function () { | |
@@ -85,12 +86,38 @@ SelectView.prototype.render = function () { | |
this.updateSelectedOption(); | |
if (this.options.isCollection) { | |
- this.options.on('add remove reset', function () { | |
+ this.options.on('add remove reset', function (model, arg2) { | |
+ var newModels, refreshModel; | |
+ var setValueFirstModel = function() { | |
+ if (!this.options.length) return; | |
+ if (this.yieldModel) this.setValue(this.options.models[0]); | |
+ else this.setValue(this.options.models[0][this.idAttribute]); | |
+ }.bind(this); | |
+ | |
+ // test if current value removed | |
+ if (model === this.value || model[this.idAttribute] === this.value) { | |
+ refreshModel = true; | |
+ } else if (arg2 && arg2.previousModels) { | |
+ // test if reset occurred | |
+ newModels = model.models; | |
+ try { | |
+ // if current value in the new option set, no action required | |
+ this.getOptionByValue(this.value); | |
+ } catch(err) { | |
+ // value not present, new option | |
+ refreshModel = true; | |
+ } | |
+ } | |
this.renderOptions(); | |
+ if (refreshModel) { | |
+ setValueFirstModel(); | |
+ } else { | |
this.updateSelectedOption(); | |
+ } | |
}.bind(this)); | |
} | |
+ this.validate(this.eagerValidate ? false : true, true); | |
this.rendered = true; | |
return this; | |
@@ -155,8 +182,12 @@ SelectView.prototype.updateSelectedOption = function () { | |
var lookupValue = this.value; | |
if (lookupValue === null || lookupValue === undefined || lookupValue === '') { | |
+ if (this.unselectedText) { | |
this.select.selectedIndex = 0; | |
return this; | |
+ } else if (!this.options.length && this.value === null) { | |
+ return this; | |
+ } | |
} | |
// Pull out the id if it's a model | |
@@ -164,7 +195,8 @@ SelectView.prototype.updateSelectedOption = function () { | |
lookupValue = lookupValue && lookupValue[this.idAttribute]; | |
} | |
- if (lookupValue || lookupValue === 0) { | |
+ if (lookupValue || lookupValue === 0 || lookupValue === null) { | |
+ if (lookupValue === null) lookupValue = ''; // DOM sees only '' empty value | |
for (var i = this.select.options.length; i--; i) { | |
if (this.select.options[i].value == lookupValue) { | |
this.select.selectedIndex = i; | |
@@ -198,23 +230,52 @@ SelectView.prototype.clear = function() { | |
* @return {SelectView} this | |
*/ | |
SelectView.prototype.reset = function() { | |
- if(this.startingValue !== undefined) this.setValue(this.startingValue, true); | |
- return this; | |
+ return this.setValue(this.startingValue, true); | |
}; | |
-SelectView.prototype.setValue = function (value, skipValidationMessage) { | |
- var option; | |
+SelectView.prototype.setValue = function (value, skipValidationMessage, init) { | |
+ var option, model, nullValid; | |
+ | |
if (value === null || value === undefined || value === '') { | |
this.value = null; | |
+ | |
+ // test if null is a valid option | |
+ if (this.unselectedText) { | |
+ nullValid = true; | |
+ } else { | |
+ try { | |
+ this.value = this.getOptionByValue(null); | |
+ nullValid = true; | |
+ } catch(err) { | |
+ // null not present in option set | |
+ } | |
+ } | |
+ | |
+ // empty value requested to be set. This may be because the field is just | |
+ // initializing. If initializing and `null` isn't in the honored option set | |
+ // set the select to the 0-th index | |
+ if (init && this.options.length && !nullValid) { | |
+ // no initial value passed, set initial value to first item in set | |
+ if (this.options.isCollection) { | |
+ model = this.options.models[0]; // or equiv to get first option in set | |
+ this.value = this.yieldModel ? model : model[this.idAttribute]; | |
+ } else { | |
+ if (isArray(this.options[0])) { | |
+ this.value = this.options[0][0]; | |
+ } else { | |
+ this.value = this.options[0]; | |
+ } | |
+ } | |
+ } | |
} else { | |
// Ensure corresponding option exists before assigning value | |
option = this.getOptionByValue(value); | |
this.value = isArray(option) ? option[0] : option; | |
} | |
this.validate(skipValidationMessage); | |
- this.updateSelectedOption(); | |
+ if (this.select) this.updateSelectedOption(); | |
if (this.parent) this.parent.update(this); | |
- return this; | |
+ return this.value; | |
}; | |
SelectView.prototype.validate = function (skipValidationMessage) { | |
@@ -227,10 +288,10 @@ SelectView.prototype.validate = function (skipValidationMessage) { | |
if (this.required && !this.value && this.value !== 0) { | |
this.valid = false; | |
- this.toggleMessage(skipValidationMessage, this.requiredMessage); | |
+ if (this.select) this.toggleMessage(skipValidationMessage, this.requiredMessage); | |
} else { | |
this.valid = true; | |
- this.toggleMessage(skipValidationMessage); | |
+ if (this.select) this.toggleMessage(skipValidationMessage); | |
} | |
return this.valid; | |
@@ -241,7 +302,9 @@ SelectView.prototype.validate = function (skipValidationMessage) { | |
* @return {SelectView} this | |
*/ | |
SelectView.prototype.beforeSubmit = function () { | |
- this.setValue(this.select.options[this.select.selectedIndex].value); | |
+ // the belog doesn't work. setValue may expect object, numbers, etc. the | |
+ // below always attempts to set a string. | |
+ // this.setValue(this.select.options[this.select.selectedIndex].value); | |
return this; | |
}; | |
@@ -256,6 +319,7 @@ SelectView.prototype.getOptionByValue = function(value) { | |
// find value in collection, error if no model found | |
if (this.options.indexOf(value) === -1) model = this.getModelForId(value); | |
else model = value; | |
+ if (!model) throw new Error('model or model-id not found in options collection'); | |
return this.yieldModel ? model : model[this.idAttribute]; | |
} else if (isArray(this.options)) { | |
// find value value in options array | |
diff --git a/test/index.js b/test/index.js | |
index 29bca6e..1fa58a6 100644 | |
--- a/test/index.js | |
+++ b/test/index.js | |
@@ -142,8 +142,12 @@ suite('Utility Methods', function (s) { | |
var select = view.el.querySelector('select'); | |
t.equal(select.options[select.selectedIndex].value, 'two'); | |
+ try { | |
view.clear(); | |
- t.equal(select.options[select.selectedIndex].value, 'one'); | |
+ t.ok(false, 'view cleared without null option'); | |
+ } catch(err) { | |
+ t.ok(true, 'view unable to clear without null option'); | |
+ } | |
})); | |
s.test('clear on view with `unselectedText`', sync(function (t) { | |
@@ -161,7 +165,6 @@ suite('Utility Methods', function (s) { | |
view.clear(); | |
t.equal(select.options[select.selectedIndex].value, ''); | |
t.equal(select.options[select.selectedIndex].text, 'Please choose:'); | |
- view.validate(); | |
t.equal(view.valid, true); | |
})); | |
@@ -176,10 +179,13 @@ suite('Utility Methods', function (s) { | |
var select = view.el.querySelector('select'); | |
t.equal(select.options[select.selectedIndex].value, 'two'); | |
+ try { | |
view.clear(); | |
- t.equal(select.options[select.selectedIndex].value, 'one'); | |
+ t.ok(false, 'view cleared without null option'); | |
+ } catch(err) { | |
+ t.ok(true, 'view unable to clear without null option'); | |
+ } | |
t.equal(view.value, null); | |
- view.validate(); | |
t.equal(view.valid, false); | |
})); | |
@@ -233,25 +239,25 @@ suite('Utility Methods', function (s) { | |
t.equal(select.options[select.selectedIndex].value, 'three'); | |
view.reset(); | |
- t.equal(select.options[select.selectedIndex].value, 'three'); | |
- t.equal(view.value, 'three'); | |
+ t.equal(select.options[select.selectedIndex].value, 'one'); | |
+ t.equal(view.value, 'one'); | |
})); | |
s.test('beforeSubmit', sync(function (t) { | |
- view = new SelectView({ | |
- name: 'word', | |
- options: arr, | |
- required: true | |
- }); | |
+ // view = new SelectView({ | |
+ // name: 'word', | |
+ // options: arr, | |
+ // required: true | |
+ // }); | |
- var select = view.el.querySelector('select'); | |
- t.equal(select.options[select.selectedIndex].value, 'one'); | |
+ // var select = view.el.querySelector('select'); | |
+ // t.equal(select.options[select.selectedIndex].value, 'one'); | |
- t.equal(view.valid, false); | |
- t.equal(view.value, null); | |
- view.beforeSubmit(); | |
- t.equal(view.value, 'one'); | |
- t.equal(view.valid, true); | |
+ // t.equal(view.valid, false); | |
+ // t.equal(view.value, null); | |
+ // view.beforeSubmit(); | |
+ // t.equal(view.value, 'one'); | |
+ // t.equal(view.valid, true); | |
})); | |
}); | |
@@ -567,6 +573,7 @@ suite('With ampersand collection', function (s) { | |
{ id: null, someOtherKey: 'bar', title: 'Option null' }, | |
{ id: 2, someOtherKey: 'baz', title: 'Option two' }, | |
]); | |
+ | |
view = new SelectView({ | |
name: 'testNullId', | |
options: coll, | |
@@ -579,10 +586,10 @@ suite('With ampersand collection', function (s) { | |
t.equal(optionNodes.length, 3); | |
t.equal(optionNodes[0].value, '0', 'option before null model has correct value'); | |
- t.equal(optionNodes[0].textContent, 'Option zero'); | |
+ t.equal(optionNodes[0].textContent, 'Option zero', 'selected option should be Option zero'); | |
- t.equal(view.value, null); // null option set by default when no value provided | |
- t.equal(optionNodes[1].value, ''); | |
+ t.equal(view.value, coll.models[1]); // null option set by default when no value provided | |
+ t.equal(optionNodes[1].value, '', 'selected option should be empty string'); | |
t.equal(optionNodes[2].value, '2', 'option after null model has correct value'); | |
t.equal(optionNodes[2].textContent, 'Option two'); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment