Possible to allow key's with '.'s in them?
sorahn opened this issue · comments
I'm looking for a way to preserve keys that have .
s in to use the same syntax as lodash's set/get.
Ideally something like this:
// Input
{
some: {
'key.with.dots': value
}
}
// Output
{
some['key.with.dots']: value
}
The problem I've found with using the transformKey
option is they still get the .
joining them.
I have this:
const flatData = flatten(data, {
transformKey: key => (key.includes('.') ? `['${key}']` : key),
});
But the output looks like this. (extra .
after some
)
{
some.['key.with.dots']: value
}
I've worked around the issue for now by looping through the flattend data and doing a string replace on .[
with [
.
const fixedData = Object.entries(flatData).reduce((acc, [key, value]) => {
const newKey = key.includes('.[') ? key.replace('.[', '[') : key;
acc[newKey] = value;
return acc;
}, {});
@sorahn I think a feature would need to be added. But if you can use this package to unflatten as well, then you could just use a different delimiter
like /
. In which case, without transformKey
, you would get:
{
"some/key.with.dots": value
}
Using the same delimiter when unflattening you would get your original structure.
If you have /
in your keys, try using transformKey
with something like encodeURIComponent
. (decodeURIComponent
when unflattening)
@rgraffbrd Hmm, that might work. I'd have to think through it. We feed the flattened data into formControlNames (angular), then use lodash for updates (set/omit
fields) and comparisons to the original data (get
).
@sorahn Not up on my Angular, but are you essentially saying that you set a form control's name to the full path and then, using lodash, you patch the original data/object structure from a flattened object with the changes?
Yes that's pretty close. We flatten the object. and use the path as the form name for angular to manage. so roughly <input name="foo['bar.baz']">
, Then we listen to all the form value changes where you get a callback that looks something like this.
(path, value) => {
if (value === null) {
return omit(path, value, data)
}
return set(path, value, data)
}
elsewhere, we are also using get
to compare to the original value to mark a field as edited. So when you pass the path
into our component it both sets it on the <input>
and uses it to check to see if the field was edited.