J3.x

Using the JToolbar class in the frontend

From Joomla! Documentation

This page contains changes which are not marked for translation.

In the Joomla administrator panel a common toolbar system is provided to present common action items to the user, such as deleting records, publishing items, etc. This toolbar can also be used in the front-end, for presenting lists to the user, but some code will need to be manually brought into the front-end context that is not automatically provided there.

There are several advantages to doing this:

  • Much of the code for creating and rendering the toolbar will still be provided by the Joomla framework, reducing the amount of code you have to write
  • From a UI coding and theming perspective, code rendered by the Joomla framework is guaranteed to be compatible and theme-capable
  • From a user perspective, you are providing a consistent experience that they recognise and can utilise immediately


How are toolbars rendered in the back-end?

Two classes are used primarily to render a toolbar into the UI:

In the back-end layout, there is a module called mod_toolbar, and an associated page location called toolbar into which a page's toolbar module is rendered:

$toolbar = JToolbar::getInstance('toolbar')->render('toolbar');

What work is needed in the front-end to support toolbars?

In the frontend we don't have:

  • A module that renders the toolbar
  • A module position "toolbar" in the template
  • Styling for the Toolbar and its components

In order to use a Toolbar object in the front-end, we will need to replicate these pieces of functionality, mostly by stealing them wholesale from the back-end!


Step 1: Defining a Toolbar in your view

In your view file, use the ToolbarHelper class to create a function that generates and renders your toolbar. You'll call this method from the view to put your toolbar in place.

use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\View\HtmlView;
use Joomla\CMS\Toolbar\ToolbarHelper;
use Joomla\CMS\Toolbar\Toolbar;

class MyExtensionViewMyView extends HtmlView {

    // ...

    protected function renderToolbar(): string {
        $title = Text::_('COM_MYEXTENSION_SOME_TITLE');
        
        ToolbarHelper::title($title);
        ToolbarHelper::addNew('youritem.add', 'COM_MYEXTENSION_BUTTON_CODE_NEW');
        ToolbarHelper::back()

        return Toolbar::getInstance()->render();
    }

}

As you can see, we are using the ToolbarHelper class to add a title to the bar, a "new item" button that will call the youritem.add action when clicked, and a back button. The ToolbarHelper has many assistance methods for different actions, such as handling list items, rendering a preferences link, and so on. To see the full list of available methods, see ToolbarHelper's source code.

Then, at the location in your view template that you wish the toolbar to appear:

<?= $this->renderToolbar(); ?>

This will render your toolbar out to the page. However, it will look pretty awful at present, because we have not yet brought in the necessary CSS to style it.


Step 2: Including styling for the Toolbar

The styles required for the toolbar are part of the standard Isis control panel theme, and can be generated easily via Less. Below is an extract of that CSS code, corrected for use in the front-end. Create a file called toolbar.css in an appropriate place within your extension and add this code into it.

Styling code for the Toolbar, taken from the Isis template. Click to expand.
/* 
 * Generated by LESS from the standard Isis administrator theme
 * Some styles related to colour have been removed, to prevent
 * issues with the user's front-end theme
 */

/* Subhead */
.subhead {
  color: #0C192E;
  text-shadow: 0 1px 0 #FFF;
  margin-bottom: 10px;
  min-height: 51px;
}
.subhead-collapse {
  margin-bottom: 19px;
}
.subhead-collapse.collapse {
  height: auto;
  overflow: visible;
}
.btn-toolbar {
  margin-bottom: 5px;
}
.btn-toolbar .btn-wrapper {
  display: inline-block;
  margin: 0 0 8px 5px;
}
.subhead-fixed {
  position: fixed;
  width: 100%;
  top: 30px;
  z-index: 100;
}
@media (max-width: 767px) {
  /* Fix ios scrolling inside bootstrap modals */
  body {
    -webkit-overflow-scrolling: touch;
  }
  .subhead {
    margin-left: -20px;
    margin-right: -20px;
    padding-left: 10px;
    padding-right: 10px;
  }
}
.subhead h1 {
  font-size: 17px;
  font-weight: normal;
  margin-left: 10px;
  margin-top: 6px;
}
/* Toolbar */
#toolbar {
  margin-bottom: 2px;
  margin-top: 12px;
}
#toolbar .btn {
  line-height: 24px;
  margin-right: 4px;
  padding: 0 10px;
}
#toolbar .btn-success {
  min-width: 148px;
}
#toolbar .btn-primary [class^="icon-"],
#toolbar .btn-warning [class^="icon-"],
#toolbar .btn-danger [class^="icon-"],
#toolbar .btn-success [class^="icon-"],
#toolbar .btn-info [class^="icon-"],
#toolbar .btn-inverse [class^="icon-"],
#toolbar .btn-primary [class*=" icon-"],
#toolbar .btn-warning [class*=" icon-"],
#toolbar .btn-danger [class*=" icon-"],
#toolbar .btn-success [class*=" icon-"],
#toolbar .btn-info [class*=" icon-"],
#toolbar .btn-inverse [class*=" icon-"] {
  background-color: transparent;
  border-right: 0;
  border-left: 0;
  width: 16px;
  margin-left: 0;
  margin-right: 0;
}
#toolbar #toolbar-options,
#toolbar #toolbar-help {
  float: right;
}
#toolbar [class^="icon-"],
#toolbar [class*=" icon-"] {
  background-color: #e6e6e6;
  border-radius: 3px 0 0 3px;
  border-right: 1px solid #b3b3b3;
  height: auto;
  line-height: inherit;
  margin: 0 6px 0 -10px;
  opacity: 1;
  text-shadow: none;
  width: 28px;
  z-index: -1;
}
#toolbar iframe .btn-group .btn {
  margin-left: -1px !important;
}
html[dir=rtl] #toolbar #toolbar-options,
html[dir=rtl] #toolbar #toolbar-help {
  float: left;
}
@media (max-width: 767px) {
  .subhead-fixed {
    position: static;
    width: auto;
  }
}
/* Subhead (toolbar) Collapse Button */
.btn-subhead {
  display: none;
}
@media (min-width: 480px) {
  #filter-bar {
    height: 29px;
  }
}
@media (max-width: 479px) {
  .navbar .btn {
    margin: 0;
  }
  .btn-subhead {
    display: block;
    margin: 10px 0;
  }
  .subhead-collapse.collapse {
    height: 0;
    overflow: hidden;
  }
  .btn-toolbar .btn-wrapper {
    display: block;
    margin: 0px 10px 5px 10px;
  }
  .btn-toolbar .btn-wrapper .btn {
    width: 100% !important;
  }
  .subhead {
    background: none repeat scroll 0 0 transparent;
    border-bottom: 0 solid #dedede;
  }
  #toolbar [class^="icon-"],
  #toolbar [class*=" icon-"] {
    background-color: transparent;
    border-right: medium none;
    width: 10px;
  }
}
@media (max-width: 319px) {
  .view-login .navbar-fixed-bottom {
    display: none;
  }
}

With this code saved in the file, register the stylesheet inside your view file's display() method, during document setup:

use Joomla\CMS\Factory;
use Joomla\CMS\Uri\Uri;

class MyExtensionViewMyView extends HtmlView {

    // ...

    function display($tpl = null) {

        // ...

        $document = Factory::getDocument();
        $document->addStyleSheet(Uri::root() . '/components/com_myextension/path/to/your/toolbar.css');

    }

}

Your toolbar should now be styled appropriately.


Restricting actions by permission

It's usually a good idea to have your toolbar buttons restricted according to the active user's permissions. This can be easily done using the ContentHelper class:

use Joomla\CMS\Helper\ContentHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\View\HtmlView;
use Joomla\CMS\Toolbar\ToolbarHelper;
use Joomla\CMS\Toolbar\Toolbar;

class MyExtensionViewMyView extends HtmlView {

    // ...

    protected function renderToolbar(): string {        
        $this->canDo = ContentHelper::getActions('com_myextension');
        $title = Text::_('COM_MYEXTENSION_SOME_TITLE');

        ToolbarHelper::title($title);

        if ($this->canDo->get('core.create')) {
            ToolbarHelper::addNew('youritem.add', 'COM_MYEXTENSION_BUTTON_CODE_NEW');
        }
        
        ToolbarHelper::back();
    }

}


Handling List Actions

Depending on the methods and actions you enable in your Toolbar, you may need to emulate a few other elements of the back-end form handling code. As list-handling is such a common use case, this section will show how to integrate those tasks into your front-end view.

This section will not describe general list handling - using the ListModel class, generating a list query, pagination, etc - as those are documented elsewhere.


Step 1: Enabling the list functionality

In the display() method of your view file, use Joomla's HtmlHelper class to load the appropriate Javascript to handle lists.

use Joomla\CMS\HTML\HTMLHelper;

class MyExtensionViewMyView extends HtmlView {

    // ...

    function display($tpl = null) {

        // ...

        HTMLHelper::_('formbehavior.chosen', 'select');

    }

}

This will enable the Javascript and other front-end assets that are needed for list functionality in the toolbar.


Step 2: Defining the Toolbar

You'll need to define the buttons that you wish to appear, and the actions they trigger. The most common options to use with a list are obviously add, edit and delete:

use Joomla\CMS\Helper\ContentHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\View\HtmlView;
use Joomla\CMS\Toolbar\ToolbarHelper;
use Joomla\CMS\Toolbar\Toolbar;

class MyExtensionViewMyView extends HtmlView {

    // ...

    protected function renderToolbar(): string {        
        $this->canDo = ContentHelper::getActions('com_myextension');
        $title = Text::_('COM_MYEXTENSION_SOME_TITLE');

        ToolbarHelper::title($title);

        if ($this->canDo->get('core.create')) {
            ToolbarHelper::addNew('youritem.add', 'COM_MYEXTENSION_BUTTON_CODE_NEW');
        }
        
        if ($this->canDo->get('core.edit') || $this->canDo->get('core.edit.own')) {
            ToolbarHelper::editList('youritem.edit', 'COM_MYEXTENSION_BUTTON_CODE_EDIT');
        }
        
        if ($this->canDo->get('core.delete')) {
            ToolbarHelper::deleteList('COM_MYEXTENSION_DELETE_CONFIRM', 'youritem.delete', 'COM_MYEXTENSION_BUTTON_CODE_DELETE');
        }
    }

}

The implementation of these actions - youritem.edit and so on - is left as an exercise for the reader, as the code for those is very dependent on your extension's implementation and not really relevant to the toolbar. However, if you're unsure how to proceed, here are a few tips:

  • To check for an item being edited and retrieve it on your create/edit page, use $this->get('Item'); in your view's display() method
  • To retrieve the list of items being selecetd when processing an action such as "delete", use $this->input->get('cid', array(), 'array'); in your controller
  • For working examples of how to handle group deletes, see the control panel's AdminController and AdminModel classes


Step 3: Rendering the list

At the top of your list in your view template, you will need to wrap the list in a form, and add a few hidden fields as shown below. These hidden fields will be set by the Toolbar's Javascript as actions and items are selected.

    <form action="<?= Route::_('index.php?option=com_myextension&view=thisview') ?>" method="post" id="adminForm" name="adminForm">
        <?= HTMLHelper::_('form.token'); ?>
        <input type="hidden" name="option" value="com_myextension">
        <input type="hidden" name="task" value="" />
        <input type="hidden" name="boxchecked" value="0" />

        <!-- Rest of list -->

Naturally, you will want to add a checkbox to each row of your item list, so that they can be selected and acted on by the toolbar. This checkbox can be easily rendered using the HtmlHelper class:

    <?php foreach ($this->items as $i => $row) : ?>
        <tr>
            <td>
                <?= HTMLHelper::_('grid.id', $i, $row->id); ?>
            </td>

            <!-- Other columns in the list -->

        </tr>
    <?php endforeach; ?>

If you wish to add a "check all" checkbox to the column header, this can also be provided by HtmlHelper:

    <thead>
        <tr>
            <th width="2%">
                <?= HTMLHelper::_('grid.checkall'); ?>
            </th>

            <!-- Other columns in the list -->

        </tr>
    </thead>


Routing and SEF URLs

Documentation all together tranparent small.png
Under Construction

This article or section is in the process of an expansion or major restructuring. You are welcome to assist in its construction by editing it as well. If this article or section has not been edited in several days, please remove this template.
This article was last edited by GregJPreece (talk| contribs) 7 months ago. (Purge)


Custom frontend buttons

Documentation all together tranparent small.png
Under Construction

This article or section is in the process of an expansion or major restructuring. You are welcome to assist in its construction by editing it as well. If this article or section has not been edited in several days, please remove this template.
This article was last edited by GregJPreece (talk| contribs) 7 months ago. (Purge)