diff --git a/wagtail_react_streamfield/blocks/block.py b/wagtail_react_streamfield/blocks/block.py index 75711b9..8ffc0ef 100644 --- a/wagtail_react_streamfield/blocks/block.py +++ b/wagtail_react_streamfield/blocks/block.py @@ -16,6 +16,19 @@ def get_default(self): default = default() return default + def get_children_errors(self, errors): + if errors: + if len(errors) > 1: + # We rely on Block.get_children_errors throwing + # a single ValidationError with a specially crafted 'params' + # attribute that we can pull apart and distribute + # to the child blocks. + raise TypeError( + 'Block.get_children_errors unexpectedly ' + 'received multiple errors.' + ) + return errors.as_data()[0].params + def prepare_value(self, value, errors=None): """ Returns the value as it will be displayed in react-streamfield. diff --git a/wagtail_react_streamfield/blocks/list_block.py b/wagtail_react_streamfield/blocks/list_block.py index 6e4066e..6681e90 100644 --- a/wagtail_react_streamfield/blocks/list_block.py +++ b/wagtail_react_streamfield/blocks/list_block.py @@ -54,8 +54,7 @@ def value_from_datadict(self, data, files, prefix): for child_block_data in data['value']] def prepare_value(self, value, errors=None): - children_errors = (None if errors is None - else errors.as_data()[0].params) + children_errors = self.get_children_errors(errors) if children_errors is None: children_errors = [None] * len(value) prepared_value = [] @@ -67,7 +66,7 @@ def prepare_value(self, value, errors=None): 'type': self.child_block.name, 'hasError': bool(child_errors), 'value': self.child_block.prepare_value(child_value, - errors=errors), + errors=child_errors), }) if html is not None: child_value['html'] = html diff --git a/wagtail_react_streamfield/blocks/stream_block.py b/wagtail_react_streamfield/blocks/stream_block.py index 36707b5..a4092ac 100644 --- a/wagtail_react_streamfield/blocks/stream_block.py +++ b/wagtail_react_streamfield/blocks/stream_block.py @@ -53,8 +53,9 @@ def value_from_datadict(self, data, files, prefix): def prepare_value(self, value, errors=None): if value is None: return [] - children_errors = ({} if errors is None - else errors.as_data()[0].params) + children_errors = self.get_children_errors(errors) + if children_errors is None: + children_errors = {} prepared_value = [] for i, stream_child in enumerate(value): child_errors = children_errors.get(i) diff --git a/wagtail_react_streamfield/blocks/struct_block.py b/wagtail_react_streamfield/blocks/struct_block.py index b694968..5260f85 100644 --- a/wagtail_react_streamfield/blocks/struct_block.py +++ b/wagtail_react_streamfield/blocks/struct_block.py @@ -58,8 +58,9 @@ def value_from_datadict(self, data, files, prefix): ]) def prepare_value(self, value, errors=None): - children_errors = ({} if errors is None - else errors.as_data()[0].params) + children_errors = self.get_children_errors(errors) + if children_errors is None: + children_errors = {} prepared_value = [] for k, child_block in self.child_blocks.items(): child_errors = (None if children_errors is None @@ -71,7 +72,8 @@ def prepare_value(self, value, errors=None): 'id': str(uuid4()), 'type': k, 'hasError': bool(child_errors), - 'value': child_block.prepare_value(child_value, errors=errors), + 'value': child_block.prepare_value(child_value, + errors=child_errors), }) if html is not None: child_value['html'] = html diff --git a/wagtail_react_streamfield/monkey_patch.py b/wagtail_react_streamfield/monkey_patch.py index c38ca9b..c0c289e 100644 --- a/wagtail_react_streamfield/monkey_patch.py +++ b/wagtail_react_streamfield/monkey_patch.py @@ -63,9 +63,9 @@ def patch(): _patch_streamfield_panel() _patch_block_widget() _patch_with(Block, NewBlock, - 'FIELD_NAME_TEMPLATE', 'get_default', 'prepare_value', - 'get_instance_html', 'definition', 'html_declarations', - 'all_html_declarations') + 'FIELD_NAME_TEMPLATE', 'get_default', 'get_children_errors', + 'prepare_value', 'get_instance_html', 'definition', + 'html_declarations', 'all_html_declarations') Block._meta_class.closed = False _patch_with(BaseStreamBlock, NewBaseStreamBlock, 'definition', 'sorted_child_blocks', 'render_list_member',