Access nested value of initialValues via attribute
Hi. Thanks for your work.
Is there any chance to have possibility to access nested value in initialValues through the attribute field?
For example if I have deeply nested initialValues I would like to have possibility to set attribute like
items.0.some.value
Hi @vasilich6107, I'm glad you find this package useful.
I haven't considered this yet, sounds like an interesting idea worth trying but maybe a bit challenging to implement.
Would be awsome to have this! Maybe have a look into sembast package could help you to implement it. There is a implementation like that for order and filter in a query :) https://github.com/tekartik/sembast.dart/blob/master/sembast/lib/src/api/field.dart https://github.com/tekartik/sembast.dart/blob/master/sembast/doc/queries.md#sortingquerying-on-nested-field
I am trying to implement this, guide me if I am on the right track. I have written two methods
- Extracts the nested value from the map.
- Generates the map according to the given attribute.
Works fine for me, any suggestions?
dynamic getInitialValue(String attribute, dynamic initialValue) {
var props = attribute.split('.');
//if property is not nested return its value from map
if (props.length < 2)
return (initialValue?.containsKey(attribute) ?? false)
? initialValue[attribute]
: null;
//iterate to find the nested value
//to track if current value is a Map or a List
var isMap = initialValue is Map;
//holds the map values
Map<String, dynamic> map = isMap ? initialValue : null;
//holds the list values
List list = isMap ? null : initialValue;
//loop all props
for (var i = 0; i < props.length - 1; i++) {
//if prop is key for list we need to convert it to INT
var key = isMap ? props[i] : int.parse(props[i]);
//if the next prop is a Map type then assign it to the map variable
if ((isMap && map[key] is Map) || (!isMap && list[key] is Map)) {
map = isMap ? map[key] : list[key];
//this tells if the current value is stored in the map or list variable
isMap = true;
}
//else of its a List type then assign it to the list varaible
else if ((isMap && map[key] is List) || (!isMap && list[key] is List)) {
list = isMap ? map[key] : list[key];
//this tells if the current value is stored in the map or list variable
isMap = false;
}
}
return isMap ? map[props.last] : list[int.parse(props.last)];
}
//recursively generates the map accroding to the attribute
dynamic getMap(List<String> props, dynamic value, dynamic map) {
if (props.isEmpty) return value;
if (props.length == 1) return {...map ?? {}, props.single: value};
//if the next prop is an integer then we have a list
var key = int.tryParse(props[1]);
if (key != null) {
var list = map == null ? [] : [...(map[props.first] ?? {})];
//if list is shorter than the provided index append null objects to list till we have the requred length of list
if (list.length <= key)
list.addAll(List.generate(key + 1 - list.length, (index) => null));
list[key] = getMap(props.sublist(2), value, list[key]);
return {...map ?? {}, props.first: list};
} else {
return {
...map ?? {},
props.first:
getMap(props.sublist(1), value, map == null ? {} : map[props.first])
};
}
}
Map<String, dynamic> initialValue = {
"prop1": {
"list": [
{"key1": "value1"},
{"key2": "value2"},
{"key3": "value3"},
"value4"
]
},
"prop2" : {"prop3" : {"prop4": "prop4 Value"}}
};
print(getInitialValue("prop1.list.0.key1", initialValue));
print(getInitialValue("prop2.prop3.prop4", initialValue));
print(getMap("prop1.list.0.key1".split('.'), "new Value 1", initialValue));
print(getMap("prop2.prop3.prop4".split('.'), "new porp4 Value", initialValue));
Any chance this would be implemented or any alternative solution?
I ended up flattening the map before assigning as initial value, and use innerObject.field as field name. I am assuming we can do that flattening inside framework.
Hi! If someone has a solution for this, please feel free to open a PR. Thanks!
Consider nested FormBuilder, like this
FormBuilder(
// ...
FormBuilderTextField(
name: 'foo',
// ...
),
NestedFormBuilder( // new class
name: 'inner',
// ...
FormBuilderTextField(
name: 'bar',
// ...
),
),
// ...
)
value example:
{
"foo": "some input value",
"inner":{
"bar" : "some inner input value"
}
}
Consider nested
FormBuilder, like thisFormBuilder( // ... FormBuilderTextField( name: 'foo', // ... ), NestedFormBuilder( // new class name: 'inner', // ... FormBuilderTextField( name: 'bar', // ... ), ), // ... )value example:
{ "foo": "some input value", "inner":{ "bar" : "some inner input value" } }
it work for me, I will PR soon @deandreamatias