kevinchappell / formBuilder

A jQuery plugin for drag and drop form creation
https://formbuilder.online
MIT License
2.63k stars 1.4k forks source link

Add destroy to formBuilder to remove instance #1136

Open jringeisen opened 4 years ago

jringeisen commented 4 years ago

Description:

I have everything working as expected on a single page application built with Vue, except when I use the formBuilder in a modal. When I initially open the modal there is only one instance of the form builder, but if I visit a different page and return and open the modal there are now two instances of the formBuilder stacked on top of one another. Each time I repeat this there is a new instance, unless I refresh the page then it's back to one instance.

Is there a way to destroy or remove the formBuilder instance when I close the modal? I can't find anything on destroying the formBuilder instance.

Environment Details:

Expected Behavior

Anytime I open the modal there should only be one instance of the formBuilder.

Actual Behavior

If I open the modal then close it and leave the page, then return and open the modal again there are two instances of the formBuilder stacked on top of each other.

Steps to Reproduce

I'm assuming you would need to implement a modal on a single page application and add a formBuilder instance inside the modal. Then open the modal, close the modal, go to a different page, return back to the modal, open the modal and you should have two instances of the formBuilder.

mounted () {
    this.$root.$on('esm::'+this.$options.name+'::shown', () => {
        this.$nextTick().then(() => {
          var vm = this
          jQuery(function ($) {
            var options = {
              disabledAttrs: [
                'style', 
                'access', 
                'name', 
                'value'
              ],
              dataType: 'json',
              showActionButtons: false,
              disableFields: [
                'autocomplete',
                'date',
                'file',
                'hidden',
              ],
              typeUserAttrs: {
                text: {
                  className: {
                    label: 'Class',
                    options: {'form-input block w-full sm:text-sm sm:leading-5': 'default'}
                  }
                },
                textarea: {
                  className: {
                    label: 'Class',
                    options: {'form-input block w-full sm:text-sm sm:leading-5': 'default'}
                  }
                },
                select: {
                  className: {
                    label: 'Class',
                    options: {'form-input block w-full sm:text-sm sm:leading-5': 'default'}
                  }
                },
                number: {
                  className: {
                    label: 'Class',
                    options: {'form-input block w-full sm:text-sm sm:leading-5': 'default'}
                  }
                },
                button: {
                  className: {
                    label: 'Class',
                    value: 'inline-flex items-center px-4 py-2 border border-transparent text-sm leading-5 font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-500 focus:outline-none focus:border-indigo-700 focus:shadow-outline-indigo active:bg-indigo-700 transition ease-in-out duration-150'
                  }
                },
                'checkbox-group': {
                  className: {
                    label: 'Class',
                    value: 'form-checkbox h-4 w-4 text-indigo-600 transition duration-150 ease-in-out'
                  }
                },
                'radio-group': {
                  className: {
                    label: 'Class',
                    value: 'form-checkbox h-4 w-4 text-indigo-600 transition duration-150 ease-in-out'
                  }
                }
              },
              disabledSubtypes: {
                button: ['button','reset'],
              },
            }

            $('#create-questionnaire-form-builder').formBuilder(options).promise.then(formBuilder => {
              vm.formData.form = formBuilder
            })
          })
        })
    })
  },
jringeisen commented 4 years ago

I wish there was a cleaner way to do this. It seems like anytime I open the modal a fresh jQuery instance is established adding another formBuilder instance to the parent div. Here is what I was able to put together to make it work.

Directly underneath this code:

$('#create-questionnaire-form-builder').formBuilder(options).promise.then(formBuilder => {
     vm.formData.form = formBuilder
})

I placed this code, which is checking to see if there is more than one child and if so it removes it.

let element = document.querySelector('#create-questionnaire-form-builder')

while (element.children.length > 0) {
    element.removeChild(element.lastChild)
}

It feels hacky and I don't really like this solution. I know mixing vue and jQuery isn't ideal but there isn't another formBuilder out there that is built like this one. A cleaner solution would be to eliminate the jQuery function when the modal is closed and then retrigger it when the modal is open but I couldn't find a good way of accomplishing this. Any idea's on how I can improve this?

Jojoshua commented 2 years ago

Did you get this resolved? There is probably a way to tell vue to ignore a container.

jorgeuos commented 2 years ago

let element = document.querySelector('#create-questionnaire-form-builder')

while (element.children.length > 0) { element.removeChild(element.lastChild) }

This solved a problem I was having. There are probably cleaner ways to do this, but hey; "If it aint broken...".