Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve select view update #271

Closed
wants to merge 6 commits into from
Closed
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 71 additions & 30 deletions backbone.stickit.js
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,18 @@
// -------

var slice = [].slice;
var STICKIT_BINDVAL_KEY = 'stickit-bind-val';

// Returns value of select option
// First checks for containing custom values, e.g not string
// If such exists, then return it. If not, fallback to simple node.value
var getSelectOptionValue = function(el) {
if (el.__stickitBindVal__) {
return Backbone.$(el).data(STICKIT_BINDVAL_KEY);
} else {
return el.value;
}
};

// Evaluates the given `path` (in object/dot-notation) relative to the given
// `obj`. If the path is null/undefined, then the given `obj` is returned.
Expand Down Expand Up @@ -501,34 +513,54 @@
// If there are no `selectOptions` then we assume that the `<select>`
// is pre-rendered and that we need to generate the collection.
if (!selectConfig) {
selectConfig = {};
var getList = function($el) {
return $el.map(function(index, option) {
// Retrieve the text and value of the option, preferring "stickit-bind-val"
// data attribute over value property.
var dataVal = Backbone.$(option).data('stickit-bind-val');
return {
value: dataVal !== undefined ? dataVal : option.value,
label: option.text
};
}).get();
// simple way
$el.val(val);
return;

// I do not know if it is possible that this method might be invoked
// each time with different params. I |selectConfig| might be present
// in future calls after one call with it,
// then next code should be enable

// I left it here so you can check. If that case is not possible
// then I will remove this code. If it's possible, then I will enable it

var check = function(val) {
return _.isArray(val) || _.isObject(val);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If _.isArray(val) passes _.isObject(val) will pass as well. Check can just be _.isObject

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This behavior of _.isObject is strange to me, but thanks for correction!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean I understand why, because it's JS and Array also is object, but I just thought what that helper is more advanced.

};
if ($el.find('optgroup').length) {
list = {opt_labels:[]};
// Search for options without optgroup
if ($el.find('> option').length) {
list.opt_labels.push(undefined);
_.each($el.find('> option'), function(el) {
list[undefined] = getList(Backbone.$(el));

if (isMultiple && _.isArray(val)) {
var hasCustomValue = _.some(val, check);
} else {
var hasCustomValue = check(val);
}

if (hasCustomValue) {
$el.prop('selectedIndex', -1);

if (isMultiple) {
$el.find('option').each(function() {
var optionVal = getSelectOptionValue(this);
var self = this;

_.each(val, function(deepVal) {
if (_.isEqual(optionVal, deepVal)) {
$(self).prop('selected', true);
}
});
});
} else {
$el.find('option').each(function() {
var optionVal = getSelectOptionValue(this);

if (_.isEqual(optionVal, val)) {
$(this).prop('selected', true);
return false;
}
});
}
_.each($el.find('optgroup'), function(el) {
var label = Backbone.$(el).attr('label');
list.opt_labels.push(label);
list[label] = getList(Backbone.$(el).find('option'));
});
} else {
list = getList($el.find('option'));
$el.val(val);
}
}

Expand All @@ -538,15 +570,22 @@
selectConfig.disabledPath = selectConfig.disabledPath || 'disabled';

var addSelectOptions = function(optList, $el, fieldVal) {
var fragment = document.createDocumentFragment();

_.each(optList, function(obj) {
var option = Backbone.$('<option/>'), optionVal = obj;

var fillOption = function(text, val, disabled) {
option.text(text);
optionVal = val;
// Save the option value as data so that we can reference it later.
option.data('stickit-bind-val', optionVal);
if (!_.isArray(optionVal) && !_.isObject(optionVal)) option.val(optionVal);

if (!_.isArray(optionVal) && !_.isObject(optionVal)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here (even though it's leftover from before)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I will fix it. Thank you!

option.val(optionVal);
} else {
// Save the option value as data so that we can reference it later.
option[0].__stickitBindVal__ = true;
option.data(STICKIT_BINDVAL_KEY, optionVal);
}

if (disabled === true) option.prop('disabled', 'disabled');
};
Expand Down Expand Up @@ -583,8 +622,10 @@
});
}

$el.append(option);
option.appendTo(fragment);
});

$el.append(fragment);
};

$el.find('*').remove();
Expand Down Expand Up @@ -679,10 +720,10 @@

if ($el.prop('multiple')) {
return _.map(selected, function(el) {
return Backbone.$(el).data('stickit-bind-val');
return getSelectOptionValue(el);
});
} else {
return selected.data('stickit-bind-val');
return getSelectOptionValue(selected[0]);
}
}
}]);
Expand Down