-
Notifications
You must be signed in to change notification settings - Fork 123
Description
Describe the bug
DataModel.update only calls _parseDataModelContents when the path is root (/ or empty). For non-root paths (e.g. /todos), the raw contents List is passed directly to _updateValue, which stores it as-is. This causes a TypeError when a widget subscribes to that path expecting Map<String, Object?> — because the stored value is still the raw List<dynamic> (the A2UI adjacency-list format).
The error manifests as:
type 'List<dynamic>' is not a subtype of type 'Map<String, Object?>?' in type cast
thrown from DataModel.getValue (data_model.dart:190) when ComponentChildrenBuilder subscribes to a template's dataBinding path.
To Reproduce
- Send a
dataModelUpdateA2UI message with a non-rootpath(e.g."/todos") andcontentsin the standard adjacency-list format:
{
"dataModelUpdate": {
"surfaceId": "todo-main",
"path": "/todos",
"contents": [
{"key": "0", "valueMap": [
{"key": "id", "valueString": "abc"},
{"key": "title", "valueString": "Buy groceries"}
]},
{"key": "1", "valueMap": [
{"key": "id", "valueString": "def"},
{"key": "title", "valueString": "Finish report"}
]}
]
}
}- Have a
Listcomponent with a template bound to/todos:
{
"List": {
"children": {
"template": {
"dataBinding": "/todos",
"componentId": "item-template"
}
}
}
}- The app crashes with
type 'List<dynamic>' is not a subtype of type 'Map<String, Object?>?' in type cast.
Expected behavior
DataModel.update should parse the adjacency-list contents into a Map<String, Object?> for all paths, not just the root. The relevant code in data_model.dart:
void update(DataPath? absolutePath, Object? contents) {
if (absolutePath == null || absolutePath.segments.isEmpty) {
if (contents is List) {
_data = _parseDataModelContents(contents); // ← only called for root
}
// ...
return;
}
_updateValue(_data, absolutePath.segments, contents); // ← raw List stored as-is
}For non-root paths, contents should also be parsed through _parseDataModelContents before being stored, e.g.:
void update(DataPath? absolutePath, Object? contents) {
Object? parsedContents = contents;
if (contents is List) {
parsedContents = _parseDataModelContents(contents);
}
if (absolutePath == null || absolutePath.segments.isEmpty) {
if (parsedContents is Map) {
_data = Map<String, Object?>.from(parsedContents);
}
// ...
return;
}
_updateValue(_data, absolutePath.segments, parsedContents);
}Additional context
- Package version:
genui0.7.0 - The A2UI v0.8 specification defines
dataModelUpdate.contentsas an adjacency-list array regardless of whetherpathis specified. ComponentChildrenBuilder(widget_helpers.dart:103) subscribes withsubscribe<Map<String, Object?>>, which callsgetValue<Map<String, Object?>>→_getValue(...) as Map<String, Object?>?, triggering the cast error.- Workaround: intercept
DataModelUpdatemessages at theContentGeneratorstream level and pre-parsecontentsfrom the adjacency-list to a plainMapbefore the SDK processes them.