json-editor / json-editor

JSON Schema Based Editor
MIT License
4.47k stars 660 forks source link

Irregular behaviour when using cleave on tables #1347

Closed eduo closed 1 year ago

eduo commented 1 year ago

Hello I've found two weird behaviours when using cleave in tables:

1.-If you set the array to "minItems=n" then "n" rows will be generated by default. These rows will not have Cleave formatting, even if defined in the schema.

2.-If you have a table with no rows at all and cleave definitions, adding new rows with the ".addRow()" method updates the output but doesn't update the form (rows don't appear). If you add one row manually you'll see all the ones created programmatically.

I tried to demonstrate both things in the interactive editor, but I couldn't get the Javascript to work. I've made a demo page showing both behaviours:

https://acc.mydll.es/jobs/test/index.html

By the time the page loads the first section should have two rows, but the first row doesn't have cleave formatting and the second section should have five rows added none of which show up in the UI but if you add another one manually all six will appear.

eduo commented 1 year ago

Schema is:

{
    "title": "Test adding rows",
    "definitions": {
        "caplz": {
            "type": "object",
            "properties": {
                "amountField1": {
                    "title": "Amount 1",
                    "type": "string",
                    "options": {"cleave": {"numeral": true,"prefix": " €","tailPrefix": true}
                    },"default": ""
                }
            }
        }
    },
    "properties": {
        "caplzsone": {
            "type": "array","format": "table",
            "title": "Array set with minItems 1",
            "items": {"title": "Added row","$ref": "#/definitions/caplz"},"minItems": 4
        },
        "caplzszero": {
            "type": "array","format": "table",
            "title": "Array with no minItems",
            "items": {"title": "Added row","$ref": "#/definitions/caplz"
            }
        }
    }
}

JS adding rows and values is this:

        var editor = new JSONEditor(document.querySelector('#editor-container'), config)

        editor.on('change', function () {
            document.querySelector('#input').value = JSON.stringify(editor.getValue())
        })

        editor.on('ready', function() {
            editor.getEditor('root.caplzsone.0.amountField1').setValue(Math.random())
            editor.getEditor('root.caplzsone').addRow()
            editor.getEditor('root.caplzsone.1.amountField1').setValue(Math.random())

            editor.getEditor('root.caplzszero').addRow()
            editor.getEditor('root.caplzszero.0.amountField1').setValue(Math.random())
            editor.getEditor('root.caplzszero').addRow()
            editor.getEditor('root.caplzszero.1.amountField1').setValue(Math.random())
            editor.getEditor('root.caplzszero').addRow()
            editor.getEditor('root.caplzszero.2.amountField1').setValue(Math.random())
            editor.getEditor('root.caplzszero').addRow()
            editor.getEditor('root.caplzszero.3.amountField1').setValue(Math.random())
            editor.getEditor('root.caplzszero').addRow()
            editor.getEditor('root.caplzszero.4.amountField1').setValue(Math.random())
        }); 

While re-testing it seems the second issue happens regardless of cleave, whereas the one is about cleave formatting so it needs it.

schmunk42 commented 1 year ago

I tried to demonstrate both things in the interactive editor, but I couldn't get the Javascript to work.

Just a quick note: You need to wrap it also onready ;) https://is.gd/NZQVWB

schmunk42 commented 1 year ago

I've found two weird behaviours when using cleave in tables:

Same behavior also with cleave disabled, https://is.gd/npkDJW Do you had it working without?

schmunk42 commented 1 year ago

@germanbisurgi Is there an event to force redraw of an editor, in this case the array editor from root.caplzszero. Or actually ... addRow() should do that.

germanbisurgi commented 1 year ago

Cleave should be added before creating the JSONEditor instance.

<script src="https://cdn.jsdelivr.net/npm/@json-editor/json-editor@latest/dist/jsoneditor.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/cleave.js@1.6.0/dist/cleave.min.js"></script>
<script>

// create instance here

</script>
eduo commented 1 year ago

Ok. Thanks to both for the notes.

I had missed the ready event in the interactive editor. Now that it's corrected it shows the same behaviour as my test page:

Here is an Interactive playground with no programmatic filling of rows. You can see here that cleave properly formats the empty fields:

image

Here is an interactive playground where inside the ready event I programmatically fill some rows. You can see that cleave is not formatting those rows but it's formatting the remaining ones (for the minItems).

I believe addRow goes in before cleave is in the picture at all:

image

Also, in the second table and both with and without cleave, the programmatic addRow is not refreshing the table when there are no rows to begin with (no minItems set or is set to 0) but are refreshing it correctly when there's at least one.

@germanbisurgi Loading order was a good suggestion, but it didn't change this. The issue is also present in the interactive editor. I believe "addRows" is indirectly bypassing cleave, who may be linked to a refresh event that is not happening. That would also match with the other issue,.

@schmunk42 Thanks for the tip on the "ready" event. I managed to put the example in the interactive editor (shortner is.gd is not working for me, but as soon as I read it I understood what I missed).

As you say, addRow doesn't seem to be refreshing the table in the way it should: When the table has no rows, it doesn't update to reflect them (could it be triggering changes at the row level rather than the table level?).

When the table has schema rows (minItems) addRows doesn't take cleave formatting, as if it was filling them in before cleave goes in or without calling cleave on them.

I think in this case cleave is showing an error in addRow, where refreshing is not done properly in the table. minItems causes one effect and having no rows at all causes another.

germanbisurgi commented 1 year ago

@eduo we took a deeper look at this case. The issue is that addRow is a private method of the array editor. It is never used in isolation. The way to accomplish the goal is to use the public method setValue() like this:

jseditor.on('ready', function () {
  jseditor.getEditor('root.caplzszero').setValue([
    {
      "dateField1": Math.random(),
      "amountField1": Math.random(),
      "amountField2": Math.random(),
      "amountField3": Math.random(),
      "amountField4": Math.random()
    },
    {
      "dateField1": Math.random(),
      "amountField1": Math.random(),
      "amountField2": Math.random(),
      "amountField3": Math.random(),
      "amountField4": Math.random()
    },
  ])
})

After that single array items are already created and ready to be set:

jseditor.getEditor('root.caplzszero.0.amountField1').setValue(99999)
eduo commented 1 year ago

Understood. It's kind of weird because when creating the row you may not have data for all the fields and addRow allowed for the row to be created and filled partially only knowing the data you have but not having to know the schema for the row.

I would've expected .addRow is the same as clicking the + button on an array. I wish I had this functionality.

Adding incomplete schema doesn't usually leave the fields empty (with a validation error) like addrow + refresh would.

Nonetheless, if the method is not supposed to be used and there's no refresh mechanism, I'll rework the solution.

Was this also the reason why Cleave wasn't correcting the display in the minItems default row? (EDIT: I answer myself: No. It's unrelated. The first of a table with cleave-formatted fields will not format values added programmatically using setValue, but will add format to fields left empty

eduo commented 1 year ago

I leave this here. Might be a better test for the bug.

The schema here calls for an array with minItems = 1

Programmatically filling the array beyond the minItems limit properly applies Cleave.

If minItems is 0 then all added data is properly formatted. If minItems is 1 then the first entry will not be formatted and the second one will.

https://is.gd/AHnKR0

I've both tried adding the values one by one (knowing the rows would be there because of minItems) or adding an array of values. Same behaviour on both cases.

In the meantime, I've removed the minItems from my forms and I programmatically ensure there are enough rows validating externally.