Winter CMS resources and help articles

Simple and to the point. Optimized by the community.

Wizard style backend form tabs

0
by der_On, last modified on April 19th, 2023

This trick turns your backend form tabs into a simple wizard with prev/next buttons.

  1. Add some custom JS to your form controllers create method:
public function create()
{
    $this->addJs('$/[my-plugin-namespace]/[my-plugin-name]/assets/js/formWizard.js');
    return parent::create();
}
  1. Add the formWizard.js under assets/js/formWizard.js in your plugin:
(() => {
  /** 
     * returns first parent element matching a selector
     * @param {Element} el
     * @param {String} selector
     * @returns {Element|null}
     * /
  function querySelectorParent(el, selector) {
    if (!el.parentElement && !el.parentElement.parentElement) {
      return null;
    }
    const match = Array.from(el.parentElement.parentElement.querySelectorAll(selector))
    .filter((parent) => {
      return parent == el.parentElement;
    })[0] || null;
    if (!match) {
      return querySelectorParent(el.parentElement, selector);
    } else {
      return match;
    }
  }

  window.formWizard = {
    prev: function(btn) {
      const tabPane = querySelectorParent(btn, '.tab-pane');
      const tabNav = querySelectorParent(btn, '.control-tabs');

      if (tabNav && tabPane) {
        const currentTab = tabNav.querySelector(`a[data-target="#${tabPane.id}"]`);
        const tabs = Array.from(tabNav.querySelectorAll('a[data-toggle="tab"]'))
        .filter((tab) => {
          return tab.parentElement.style.display !== 'none';
        });
        const index = tabs.indexOf(currentTab);
        tabs[index - 1].click();
      }
    },
    next: function(btn) {
      const tabPane = querySelectorParent(btn, '.tab-pane');
      const tabNav = querySelectorParent(btn, '.control-tabs');

      if (tabNav && tabPane) {
        const currentTab = tabNav.querySelector(`a[data-target="#${tabPane.id}"]`);
        const tabs = Array.from(tabNav.querySelectorAll('a[data-toggle="tab"]'))
        .filter((tab) => {
          return tab.parentElement.style.display !== 'none';
        });
        const index = tabs.indexOf(currentTab);
        tabs[index + 1].click();
      }
    }
  };
})();
  1. Create a partial for the prev next buttons that should be present in each step under partials/form/_form_wizard_prev_next.php in your plugin:
<button
    type="button"
    onclick="formWizard.prev(this); return false;"
    class="btn btn-default"
>
    Back
</button>

<button
    type="button"
    onclick="formWizard.next(this); return false;"
    class="btn btn-primary pull-right"
>
    Continue
</button>
  1. For the first step we only need a next button. Create a partial under partials/form/_form_wizard_next.php in your plugin:
<button
    type="button"
    onclick="formWizard.next(this); return false;"
    class="btn btn-primary pull-right"
>
    Continue
</button>
  1. For the last step we need a prev and save button to finish the wizard. Create a partial under partials/form/_form_wizard_prev_save.php in your plugin:

    <button
    type="button"
    onclick="formWizard.prev(this); return false;"
    class="btn btn-default"
    >
    Back
    </button>
    
    <button
    type="button"
    data-request="onSave"
    data-request-data="close:1"
    data-hotkey="ctrl+enter, cmd+enter"
    data-load-indicator="<?= e(trans('backend::lang.form.saving')) ?>"
    class="btn btn-primary">
    <?= e(trans('backend::lang.form.create')) ?>
    </button>
  2. Now add those partials to the end of each tab in your form:

tabs:
    fields:
        someField:
            label: Some Field
            tab: First tab
        _buttons_first_tab:
            type: partial
            path: $/my-plugin-namespace/my-plugin-path/partials/form/_form_wizard_next
            tab: First tab

    someOtherField:
            label: Some Other Field
            tab: Second tab
        _buttons_second_tab:
            type: partial
            path: $/my-plugin-namespace/my-plugin-path/partials/form/_form_wizard_prev_next
            tab: Second tab

    someLastField:
            label: Some Last Field
            tab: Last tab
        _buttons_last_tab:
            type: partial
            path: $/my-plugin-namespace/my-plugin-path/partials/form/_form_wizard_prev_save
            tab: Last tab

And here you have a simple wizard using tabs.

Discussion

0 comments

We use cookies to measure the performance of this website. Do you want to accept these cookies?