jmrivas86/django-json-widget

Suggestion to use get/setText() instead of get/set() to avoid weird save/error issues

Opened this issue · 0 comments

options.onChange = function () {
    var json = editor.get();
    textarea.value=JSON.stringify(json);
}

The above piece of code has nasty behavior. According to json-editor docs, editor.get() throws an Exception when the editor doesn't contain a valid JSON value. Well, what are the implications? It saves the last valid JSON value. Few open issues are due to this behavior. For instance consider, #26 On the second attempt when clearing completely (assuming CTRL + A and Backspace), onChange triggers, and editor.get() throws exception failing to update widget.value. #47 The last known value in textarea.value is "", copy-pasting invalid json does not update its value due to the same reasons mentioned.

Possible Solution:

Changing <script> block in django_json_widget.html

<script>
    (function() {
        const container = document.getElementById("{{ widget.attrs.id }}");
        const textarea = document.getElementById("{{ widget.attrs.id }}_textarea");

        const options = {{ widget.options | safe }};
        options.onChange = function () {
            textarea.value = editor.getText();
        }

        const editor = new JSONEditor(container, options);

        const json = textarea.value;
        editor.setText(json);
        document.getElementById("{{ widget.attrs.id }}").getElementsByClassName('jsoneditor-format')[0]?.click()
    })();
</script>

Django's inbuilt form validation takes care of validating JSON text.

Hackaround (just in case changes doesn't reach code-base)

Define JSONFieldWidget as follow:

"""django_json_widget.widgets.JSONEditorWidget with custom template_name"""

from django_json_widget.widgets import JSONEditorWidget


class JSONFieldWidget(JSONEditorWidget):
    template_name = 'widgets/json_field_widget.html'

Define json_field_widget.html in the templates/widgets folder as follow:

<div {% if not widget.attrs.style %}style="height:{{widget.height|default:'500px'}};width:{{widget.width|default:'90%'}};display:inline-block;"{% endif %}{% include "django/forms/widgets/attrs.html" %}></div>

<textarea id="{{widget.attrs.id}}_textarea" name="{{ widget.name }}" required="" style="display: none">{{ widget.value }}</textarea>

<script>
    (function() {
        const container = document.getElementById("{{ widget.attrs.id }}");
        const textarea = document.getElementById("{{ widget.attrs.id }}_textarea");

        const options = {{ widget.options | safe }};
        options.onChange = function () {
            textarea.value = editor.getText();
        }

        const editor = new JSONEditor(container, options);

        const json = textarea.value;
        editor.setText(json);
        document.getElementById("{{ widget.attrs.id }}").getElementsByClassName('jsoneditor-format')[0]?.click()
    })();
</script>

That is it! Use JSONFieldWidget in place of JSONEditorWidget