jsonform / jsonform

Build forms from JSON Schema. Easily template-able. Compatible with Bootstrap 3 out of the box.
https://jsonform.github.io/jsonform/playground/index.html
MIT License
2.72k stars 553 forks source link

Advancedfieldset form folding click handle gets duplicated when jsonform gets called again causing the folded form to flick #448

Closed schnorea closed 2 weeks ago

schnorea commented 2 weeks ago

When jsonform uses advancedfieldset and the jsonform is recalled with another schema/form the click handle doesn't get cleared.

The result is that the folded part of the form starts to flicked and soon isn't able to be used.

Here is the usage of advancedfieldset as can be seen in the JsonForm Playground

{
  "schema": {
    "name": {
      "type": "string",
      "title": "Name"
    },
    "age": {
      "type": "number",
      "title": "Age"
    }
  },
  "form": [
    "name",
    {
      "type": "advancedfieldset",
      "items": [
        "age"
      ]
    }
  ]
}

The part of code responsible for this is here

// Initialize expandable sections, if any
  $('.expandable > div, .expandable > fieldset', formElt).hide();
  formElt.on('click', '.expandable > legend', function () {
    var parent = $(this).parent();
    parent.toggleClass('expanded');
    parent.find('legend').attr("aria-expanded", parent.hasClass("expanded"))
    $('> div', parent).slideToggle(100);
  });

Placing this line of code before this section looks to fix the issues

  formElt.off('click', '.expandable > legend');

So once this has been applied it should look like this.

// Initialize expandable sections, if any
  formElt.off('click', '.expandable > legend') // cleanup previous handler
  $('.expandable > div, .expandable > fieldset', formElt).hide();
  formElt.on('click', '.expandable > legend', function () {
    var parent = $(this).parent();
    parent.toggleClass('expanded');
    parent.find('legend').attr("aria-expanded", parent.hasClass("expanded"))
    $('> div', parent).slideToggle(100);
  });
sdetweil commented 2 weeks ago

I see what you say but what do you mean gets called again? the typical way to use it is to call jsonform to generate the form into a location in the dom, use it, and then destroy it... so, one time use.

schnorea commented 2 weeks ago

I must be using it wrong then. I have a form that gets filled in multiple times as other links on the page get selected. So I just pass the next forms data into the same jsonform. It had been working great until I wanted to hide some advanced details to recoup some screen space. Below is what I call.

I will try setting the meta_jsonform value to null before calling jsonForm again as it sounds like how it was intended to be used.

Great library by the way!!!

var meta_jsonform = null;

    function edit_meta(meta_data) {
      form_dirty = false;
      // Elsewhere there is a event handler like this 
      // $('body').on('input', '.controls', function(event)...
      // declares the form_dirty and adds an Icon to the forms
      // title to indicate that the values in the form have changed
      // but the form hasn't been save yet.
      //  Having a way to tell if the values have changed might be a good feature.

      // Access values directly via meta_jsonform.formDesc.value object
      meta_jsonform = $('#to-edit').jsonForm({
        schema: meta_schema,
        value: meta_data,
        form: meta_form,
        onSubmit: function (errors, meta_data) {
          if (errors) {
            console.log('Validation failed');
          } else {
            save_form(meta_data);
            form_dirty = false;
            removeIcon();
          }
        }
      });
sdetweil commented 2 weeks ago

maybe not wrong , this is my form code

// replace any form from last connection
      $("#result").html('<form id="result-form" class="form-vertical"></form>');
      // insert the new form
      $("#result-form").jsonForm(data);

your idea seems like an innocuous change tho

schnorea commented 2 weeks ago

I tried setting null didn't fix anything. The problem is i don't remove the <form> element from the dom. As you said and your code shows. I'll give that a go.

schnorea commented 2 weeks ago

Works as intended!!!! Thank you for your help!!
The key was to remove the form elements and replace them before calling jsonform on them again.

sdetweil commented 2 weeks ago

glad you worked it out.