Wagtail - How can I use a custom StructBlock with programmatically assignable default values?

I have created a StreamField for some of the site's settings. This StreamField contains a collection of a custom StructBlock, named FacetBlock. FacetBlock contains a BooleanBlock, a CharBlock, an IntegerBlock and a ChoiceBlock. Now I need to make the CharBlock translatable, which means the admin will be able to enter one text for each language available on the site.

The way I was thinking of doing this is by using another custom StructBlock, this time called TranslatableTextBlock. It would contain a ChoiceBlock, a CharBlock and some hidden input to store the complete value. Using javascript, the admin would select a language, enter the text for that language and then move on to the next language. I'm not sure yet how that would be saved the database, but I'm not even able to get that far.

Right now, I can have either the fields show up with no default value or I get a javascript error (TypeError: e is null) in vendor.js, which triggers the same error in comments.js. Here is the code I have so far. I have omitted the FacetBlock definition, because it works perfectly when reverting TranslatableTextBlock to a CharBlock.

Python code:

class TranslatableTextBlock(StructBlock):
    def __init__(self, default_text:str = None, default_language:str = None, local_blocks = None, search_index = True, **kwargs):
        local_blocks = [
            (
                "language",
                ChoiceBlock(
                    choices=LANGUAGES,
                    default=default_language if default_language else None,
                    help_text=_("Select the language for this text")
                )
            ),
            (
                "text",
                CharBlock(
                    default=default_text if default_text else None,
                    help_text=_("Enter your text in the selected language"),
                )
            )
        ]
        super().__init__(local_blocks, search_index, **kwargs)

    class Meta:
        form_classname = "struct-block translatable-text-block"
        form_template = 'blocks/translatable_text_block_admin.html'
        icon = 'doc-full'
        label = _('Translated text')
        template = 'blocks/translatable_text_block.html'


class TranslatableTextBlockAdapter(StructBlockAdapter):
    js_constructor = "website.blocks.TranslatableTextBlock"

    @cached_property
    def media(self):
        structblock_media = super().media
        return Media(
            js=structblock_media._js + ["website/js/translatable_text_block.js"],
            css=structblock_media._css
        )

register(TranslatableTextBlockAdapter(), TranslatableTextBlock)

The admin template (translatable_text_block_admin.html):

{% load wagtailadmin_tags  %}

<div class="{{ classname }}">
{% if help_text %}
    <span>
        <div class="help">
            {% icon name="help" classname="default" %}
            {{ help_text }}
        </div>
    </span>
{% endif %}
    {% for child in children %}
    {{ child }}
    <div class="w-field" data-field data-contentpath="{{ child.block.name }}">
        {% if child.block.label %}
        <label class="w-field__label" {% if child.id_for_label %}for="{{ child.id_for_label }}"{% endif %}>{{ child.block.label }}{% if child.block.required %}<span class="w-required-mark">*</span>{% endif %}</label>
        {% endif %}
        {{ child.render_form }}
    </div>
    {% endfor %}
</div>

Javascript code (translatable_text_block.js):

if (typeof TranslatableTextBlockDefinition === "undefined") {
    class TranslatableTextBlockDefinition extends window.wagtailStreamField.blocks.StructBlockDefinition {
        render(placeholder, prefix, initialState, initialError) {
            const block = super.render(placeholder, prefix, initialState, initialError);    // The error happens on this line.
            // Some custom modifications would happen here.
            return block;
        }
    }

    window.telepath.register("website.blocks.TranslatableTextBlock", TranslatableTextBlockDefinition);
}

The javascript error:

TypeError: e is null
vendor.js:2:191488
Uncaught TypeError: e is null
comments.js:1:47007

Is anyone familiar with nested StructBlock for Streamfields in admin settings? Or maybe I'm going at this the wrong way and there is an easier solution? I welcome frame challenges :)

Вернуться на верх