Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Grouping controls #1541

Open
FelipeEspinozaMe opened this issue Mar 14, 2024 · 9 comments
Open

Grouping controls #1541

FelipeEspinozaMe opened this issue Mar 14, 2024 · 9 comments

Comments

@FelipeEspinozaMe
Copy link

FelipeEspinozaMe commented Mar 14, 2024

Hello there, i'm trying to use formbuilder to create different custom controls, but i found that i made too many, so i wondered if i could group the controls that appear on the right to make a cleaner interface, i already tried

 $(document).ready(function(){
    if (window.jQuery) {  
        var observer = new MutationObserver(function(mutations) {
            mutations.forEach(function(mutation) {
                // Comprueba si se han añadido nodos
                if (mutation.addedNodes.length) {
                    // Encuentra el elemento con la clase .frmb-control
                    var frmbControl = $('.frmb-control');
                    
                    // Si se encuentra el elemento, añade el elemento de agrupación
                    if (frmbControl.length) {
                        // Crea un nuevo elemento de agrupación
                        var groupElement = $('<li class="input-control input-control-group ui-sortable-handle"><span><span class="control-icon">≡</span>Mi Grupo Personalizado</span></li>');
                        
                        // Añade un evento de clic al elemento de agrupación
                        groupElement.off('click').on('click', function() {
                           
                            customControls.toggle();
                        });
                        console.log(window.fbControls)
                        // Añade el elemento de agrupación a la barra lateral
                        frmbControl.append(groupElement);
                        console.log('xxxx', frmbControl)
                        
                        var customControls = $('li').filter(function() {
                            return ['stationCustomTable', 'binDataCustomTable'].includes($(this).data('type'));
                        }); 
                        // Si se encuentran elementos de control personalizado, añádelos al elemento de agrupación y desconecta el observador
                        var customControlsAdded = false;

                        if (customControls.length && !customControlsAdded) {
                            // Oculta los elementos de control personalizado

                            customControls.appendTo(groupElement);

                            // Marca que los elementos de control personalizado ya han sido agregados
                            customControlsAdded = true;

                            // Desconecta el observador cuando hayas terminado
                            observer.disconnect();
                        }
                    }
                }
            });
        });
        // Configura el observador para observar todo el documento y sus descendientes
        observer.observe(document, { childList: true, subtree: true });
    }
})

i would like some advice about this, or maybe there is an option there that does this instead.

@lucasnetau
Copy link
Collaborator

Hi @FelipeEspinozaMe , currently there is no option to group controls. It's a interesting enhancement.

In terms of your problem. I'm not sure why the control is being inserted twice. Are you able to set a breakpoint on the function processControl in formBuilder.js and get the stack trace for when it is called twice. That way we can see which handler or handlers are firing.

@FelipeEspinozaMe
Copy link
Author

FelipeEspinozaMe commented Mar 20, 2024

i'm actually using the mim file, i guess that the custom control loads when the builder loads, so when i group them it loads them again (its my theory), right now i got it to work this way

if (window.jQuery) {  
            var observer = new MutationObserver(function(mutations) {                    
                mutations.forEach(function(mutation) {
                    if (mutation.addedNodes.length) {
                        mutation.addedNodes.forEach(function(node) {
                            if (node.nodeType === Node.ELEMENT_NODE) { 
                                var frmbControl = $('.frmb-control');
                                var $node = $(node);
                                var $liElements = $node.find('li');  
                              
                                var groupElement = $('<li class="bg-primary text-white no-formbuilder" style="pointer-events: none;" draggable="false"><span><i class="control-icon" style="pointer-events: auto;">≡</i>Bitacora</span></li>');
//insert your groupElement
                              
                                $liElements.each(function() {
                                    var $li = $(this);
                                    if ([ 'customControlname1', 'customControlname2',  'customControlname3' ]
                                    .includes($li.data('type'))) {   
                                        if (frmbControl.length) {    
                                            $li.data('type')==='customControlname1'? groupElement.insertBefore($li) : null;        
                                            $li.hide();  
                                            groupElement.on('click', function(event) {
                                                $li.toggle();  
                                            });    
                                            observer.disconnect();
                                        }
                                    }
                                   //rest of code 
                        })
                        
                    }
                });   
            });
            observer.observe(document, { childList: true, subtree: true });
        }

@kevinchappell
Copy link
Owner

I'm not sure of that exact problem but looks like youre making good progress. I would recommend working with the source files though, the minified files are difficult to read. formBuilding has something like control groups in the inputSets option but the UI isn't nearly as nice as your's.

In the dev demo, "User Details" and "User Agreement" are examples of control groups
image

Check out the inputSets option for more details.

@FelipeEspinozaMe
Copy link
Author

i would love to, but i dont know how to import the source code in my project i tried to import it in my laravel project but it doesnt work as intender, any tip?

@rajindersinghugw

This comment was marked as off-topic.

@lucasnetau
Copy link
Collaborator

lucasnetau commented Apr 19, 2024

Hi @FelipeEspinozaMe

I had some time to look at this. The reason for the double click is the click handler for adding a control is being triggered twice, once for the control and once for the group.

This patch solves that issue

diff --git a/src/js/form-builder.js b/src/js/form-builder.js
index 1761fdf..0af1f0f 100644
--- a/src/js/form-builder.js
+++ b/src/js/form-builder.js
@@ -248,7 +248,7 @@ function FormBuilder(opts, element, $) {
     $(element).replaceWith($editorWrap)
   }
 
-  $(d.controls).on('click', 'li', ({ target }) => {
+  $(d.controls).on('click', 'li.input-control', ({ target }) => {
     //Remove initial placeholder if simply clicking to add field into blank stage
     if (h.stageIsEmpty()) {
       $stage.find(tmpRowPlaceholderClassSelector).eq(0).remove()

I'll raise a PR for this patch, it makes sense to be more specific with our selector.

@kevinchappell we could also stop propagation of the click event when we handle it here.

With two small changes to your code in the original report:

Remove input-control from the group class list, otherwise the click handler will fire twice.

var groupElement = $('<li class="input-control-group ui-sortable-handle"><span><span class="control-icon">≡</span>Mi Grupo Personalizado</span></li>');

Don't collapse the group when clicking on an input-control (UX improvement)

                              // Añade un evento de clic al elemento de agrupación
                              groupElement.off('click').on('click', function({target}) {
                                  if ($(target).closest('li.input-control').length === 0) {
                                      console.log('Click event triggered');
                                      // Muestra u oculta los elementos de control personalizado cuando se hace clic en el elemento de agrupación
                                      customControls.toggle();
                                  }
                              });

I also needed to move this flag var customControlsAdded = false; to outside the observer definition otherwise it trigger an infinite loop on Chrome.

@lucasnetau
Copy link
Collaborator

Try this version of form-builder with the patch applied

form-builder.min.js.gz

@FelipeEspinozaMe
Copy link
Author

FelipeEspinozaMe commented Apr 19, 2024

I managed to get it working for n custom controls and show them in an order it works like a charm with the patch provided
here is the final result if someone wants to implement it:

$(document).ready(function(){
            if (window.jQuery) {  
                       var customControlsAdded = false;
                       var observer = new MutationObserver(function(mutations) {
                         mutations.forEach(function(mutation) {
                        // Comprueba si se han añadido nodos
                        if (mutation.addedNodes.length) {
                            var frmbControl = $('.frmb-control');
                            if (frmbControl.length) {
                                var groupNames = ['your_group1', 'your_group2'];  //Name of the groups
                                var customControlTypes = [ //Name of the customControl
                                    ['custom_control_type1_1','custom_control_type1_2'], 
                                    ['custom_control_type2_1','custom_control_type2_2'],
                                ];
                                var groupElements = [];
                                groupNames.forEach(function(groupName, index) {
                                    var groupElement = $('<li class=" input-control-group ui-sortable-handle"><span><span class="control-icon">≡</span>' + groupName + '</span></li>'); 
                                    frmbControl.append(groupElement);
                                    groupElements.push(groupElement);
                                    var customControls = $('li').filter(function() {
                                        return customControlTypes[index].includes($(this).data('type'));
                                    });
                                    groupElement.children('span').off('click').on('click', function() {
                                        customControls.toggle();
                                    });
                                    customControls.hide();
                                    var firstCustomControl = customControls.first();
                                    groupElement.insertBefore(firstCustomControl);
                                    if (customControls.length) {
                                        customControls.appendTo(groupElement);
                                        customControlsAdded = true;
                                        observer.disconnect();
                                    }
                                });
                            }
                        }     
                    });
                });
                observer.observe(document, { childList: true, subtree: true });
            }
        })
`
still i got a question, is there a way to disable the draggable for the specific li? i tried something like this 
$(".no-formbuilder").draggable({ disabled: true });  
but without success i can drag and drop it this way witch is kind of funny actually because it works.
![imagen](https://github.com/kevinchappell/formBuilder/assets/155657424/4277d79b-7afa-4275-82d0-a47d46a59724)

@lucasnetau
Copy link
Collaborator

Will need to exclude anything that is not li.input-control (https://jqueryui.com/sortable/#items). I'll take that into account when I write the PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants