backbone.syphon
backbone.syphon copied to clipboard
Syphon.deserialze does not work with <select multiple> elements
I could definitely have something wrong on my end, but so far it seems like Syphon.serialize will take a multiselect and turn it into an array of strings, but pass the same array of strings back to Syphon.deserialize and the values do not get set. I see that the inputwriter delegates to $el.val(), so this should work OK.
On further investigation, It appears to be failing at Syphon.deserialize where the key is used to pull data:
Syphon.deserialize = function(view, data, options){
/* ... */
var value = flattenedData[key]; // <--------- This returns undefined, even though the console shows that this contains an array
inputWriter($el, value);
});
flattenedData at this point in the execution contains an array at the key of handedness, but it is not accessible for some reason.
flattenedData
gender: "Female"
guest: false
handedness[]: Array[2]
id: 37
nickname: "[email protected]"
state: null
I learned this:
flattenedData["handedness"] // undefined
flattenedData["handedness[]"] // returns expected value
I thought the [] was just a helpful chrome hint. I didn't realize it's part of the key.
I think this means that they keyExtractor for select should add [] if it's multi select. Or those brackets should never be part of the key. I'm not sure why they are there.
Since the input writer and the key extractor are both keyed by type, which does not include the multiple distinction on a select, I see two possible solutions:
- Change the deserialize method to check for a value at
key[]if a value does not exist atkey - Change the flattenData method to not add '[]' to the key, ever.
What's the best way to proceed do ya think? Is there another, better way to go?
The solution that seems easiest is here:
Syphon.deserialize = function(view, data, options){
// Build the configuration
var config = buildConfig(options);
// Get all of the elements to process
var elements = getInputElements(view, config);
// Flatten the data structure that we are deserializing
var flattenedData = flattenData(config, data);
// Process all of the elements
_.each(elements, function(el){
var $el = $(el);
var type = getElementType($el);
// Get the key for the input
var keyExtractor = config.keyExtractors.get(type);
var key = keyExtractor($el);
// Get the input writer and the value to write
var inputWriter = config.inputWriters.get(type);
var value = flattenedData[key];
if (!value) { value = flattenedData[key+'[]'] } // keys can either be `name` or `name[]`
// Write the value to the input
inputWriter($el, value);
});
Want a pull request?
The other way is to comment out line 273 of lib/amd/backbone.syphon.js:
if (_.isArray(value)){
//keyName += "[]";
hash[keyName] = value;
} else if (_.isObject(value)){
hash = flattenData(config, value, keyName);
} else {
hash[keyName] = value;
}
I'm not sure what side effects this would have though.
@derickbailey, Have you ever intend to combine these changes?
@SimpleAsCouldBe @SebastianTroc Sorry this wasn't addressed sooner. It has now been marked critical.
Multiple selects definitely do not work. Why is the keyName being suffixed with "[]" in flattenData? That's the real question.
The hotfix of @SimpleAsCouldBe (https://github.com/marionettejs/backbone.syphon/issues/25#issuecomment-19920556) worked for me. Mind the missing bracket at the end when applying the fix
Very much related to discussion in #34
:+1: Still seeing this on 0.6.2.
Just ran into this issue in 0.6.3! ++ for an fix