Skip to content

Instantly share code, notes, and snippets.

@cdaringe
Last active August 29, 2015 14:18
Show Gist options
  • Save cdaringe/2aa1dac555a0a6cb4c79 to your computer and use it in GitHub Desktop.
Save cdaringe/2aa1dac555a0a6cb4c79 to your computer and use it in GitHub Desktop.
select-view-diff
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