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

Tabs conflicts in CollectionField when using "useEntryCrudForm" and tabs #5690

Open
vlepeule opened this issue Mar 28, 2023 · 2 comments
Open

Comments

@vlepeule
Copy link

Tabs conflicts (due to same id attr) in CollectionField when using "useEntryCrudForm" and child's have tabs => Child's Tabs (in collection child's form) have same ids so javascript tab's behavior is confused.

EA version : 4.6.1

To Reproduce
Assume two related entities, parent & child Entity, with corresponding Crud Controllers.

Add a collection field to the Parent controller :

# App\Controller\Admin\ParentCrudController
// [...]
yield CollectionField::new('child')->useEntryCrudForm(ChildCrudController::class);
// [...]

Add at least two tabs to ChildCrudController :

# App\Controller\Admin\ChildCrudController
// [...]
yield FormField::addTab('First tab');
yield TextField::new('title');
yield FormField::addTab('Second tab');
yield TextField::new('description');
// [...]

Add two childs to parent, (save & refresh, bug didn't occur when adding a child with JS), and :
Child 1 "First tab" have same html id of Child 2 "First tab"
Child 1 "Second tab" have same html id of Child 2 "Second tab" ...

With duplicate id's, javascript tab's behavior is confused (child 2 trigger child 1 tabs, etc)

Fix proposal
Add unique id in :

$metadata['id'] = $fieldDto->getProperty();

E.g.

$metadata['id'] = "ea_form_tab_" . (new Ulid());

Not sure if it's the best way, but it works.

@cillian-tdsultra
Copy link

Same issue here. Is there any way to hook into the form within the CRUD controller and change the ids?

@MokryPatrik
Copy link

I've created simple js to hot fix this issue.

// public/assets/admin/js/collection-tab-fix.js 

/**
 * Function to fix duplicate tab IDs and href attributes in a collection of tabs.
 * 
 * This function targets all elements with a 'data-bs-toggle="tab"' attribute within 
 * '.nav-tabs-custom.form-tabs-tablist'. It checks for duplicates based on the href 
 * attribute and updates the duplicates to have unique href and id attributes by appending 
 * an index to them. It also updates the corresponding content div's id attribute.
 * 
 * The function is triggered on DOMContentLoaded to ensure it runs after the DOM is fully loaded.
 * Additionally, it sets up event listeners on buttons with the class 'field-collection-add-button'
 * to re-run the fix after new tabs are dynamically added, with a slight delay to ensure the tabs 
 * are in place before fixing them.
 */
function fixTabsInCollection()
{
  document.querySelectorAll('.nav-tabs-custom.form-tabs-tablist [data-bs-toggle="tab"]').forEach((tab, index) => {
    const href = tab.getAttribute('href');
    const id = tab.getAttribute('id');
    const tabsWithSameHref = document.querySelectorAll(`.nav-tabs-custom.form-tabs-tablist [href="${href}"]`);
    
    if (tabsWithSameHref.length > 1) {
      tabsWithSameHref.forEach((duplicateTab, dupIndex) => {
        // Edit only duplicates
        if (dupIndex > 0) {
          const newHref = `${href}-${dupIndex}`;
          const newId = `${id}-${dupIndex}`;
          
          // Update tab
          duplicateTab.setAttribute('href', newHref);
          duplicateTab.setAttribute('id', newId);
          
          // Find div inside group and update it
          const correspondingDiv = duplicateTab.closest('.row').querySelector(`.nav-tabs-custom.form-tabs-content ${href}`);
          if (correspondingDiv) {
            correspondingDiv.setAttribute('id', `${href.substring(1)}-${dupIndex}`);
          }
        }
      });
    }
  });
}

document.addEventListener('DOMContentLoaded', function() {
  fixTabsInCollection();
  document.querySelectorAll('.field-collection-add-button').forEach((button) => {
      button.addEventListener('click', function() {
        // Wait some time for new tab to be added
        setTimeout(fixTabsInCollection, 100);
      });
  })
});
// Controller

public function configureAssets(): Assets
{
    return parent::configureAssets()
        ->addJsFile('assets/admin/js/collection-tab-fix.js')
    ;
}

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

No branches or pull requests

3 participants