Home > Article > Backend Development > Creating a custom Form field type in Joomla sing the Modal Select example
Using the ModalSelect Form field type in Joomla 5 to simplify finding the right product, from thousands, by filtering in a modal window using category, manufacturer and search when developing an extension.
In the process of working with clients, there are tasks of various levels: someone needs a simple website of 5-6 pages. Someone needs a large catalog of goods or an online store with integrations with third-party systems using the REST API. Somebody else needs non-standard functionality for which there are no popular solutions available.
Joomla is good for development and allows you to create easily maintained code. If the requirement follows the CMS core then it has an answer for all these cases.
To complete a large project, we need to split it into smaller tasks, and I want to talk about solving one of these tasks in this article.
Customers have already created a product catalog on one of the popular components of the online store for Joomla (JoomShopping). They can select the parameters of the product, put it in the cart and make a purchase. Everything is as usual. However, now you need to add the ability to create a graphic layout for products. For example, your product is a mug or a T-shirt. And before buying, you can go to the product designer, upload your logo or photo, write a text and this layout is attached to the order in the online store. After payment, the layout goes directly to production, where the image and text are applied to your mug and sent to the address.
Since implementation of this functionality is quite time consuming, it is created as a separate product designer component. And data provider plugins will already be created, allowing you to work with one or another e-commerce component.
One of the small, applied tasks is to create connections between the goods of the online store component and the goods in the product designer component. This should be convenient and intuitive for content managers who will work on the content in the future. Therefore, it is not enough just to make a text field where the id number of the desired product will be indicated. There may be only a few dozen products in an online store, and then choosing a product for communication is not very difficult. If there are thousands of products the functionality of searching and filtering products by parameters is important. If you can filter the list of products by category, manufacturer, or find it by name among hundreds of others, your work will be much faster and easier.
See the video
This field is very similar to the work of the editor button plugins (editors-xtd group), where the data for selection is shown in the modal window: a link to the article, a short code for the module, etc.
In the Joomla administrator panel, there are different fields that need to be filled with data from other components: specify the article, menu item, contact, product, etc. Usually such fields are designed as a select option drop-down list, they can be designed as input type="text" with a datalist, but there are also convenient fields showing a list of the desired entities, with filtering, search and pagination. Not only sources within the site (various components, plugins) can act as a data source, but also third-party services available via the REST API: CRM, delivery services, external databases, other Joomla sites, and so on.
We have all seen these fields in action when selecting an article in a menu item such as "Articles -Single article", "Contacts - Single contact", or when creating an alias of the menu item - "System links - Menu Item alias". However, let's remind ourselves what they look like.
A modal article selection window.
A modal single contact selection window.
Let's take a closer look at these fields - what exactly they allow you to do. Somewhere deep inside, we understand that the main job of this field is to get the id of the selected entity and put this id in a text field. But on the screen we see something else - instead of an id number, we see the title of the article or contact. It's nice and convenient. You do not need to remember the name of the article with id 1452704. Also, the video clearly shows that if the field already has a value, the "clear" button appears. It resets the value of the field and allows you to click on the "select" button again.
In some cases, we have the opportunity to create a selected type of entity - article, contact, etc. right in the process of creating a menu item. This button works taking into account the ACL - separation of access rights in Joomla.
Imagine you are building a website and creating a "Contacts" page. If you don't have a bunch of company branches with a complex structure, then this is just the usual Joomla article in the "Uncategorized" category. And it already has all the contacts in the form of text or of variables. In ancient times, you had to create the article first, and then go to the menu items and create a menu item for it. You don't have to do that now.
And if the field already has a value, then in some cases it is possible to edit the selected entity (article, menu item, etc.) right in the process of creating a menu item.
So, using the selection field in the modal window, we can:
This is what's in front of my eyes. But in the depths of Joomla there is also a curious urlCheckin parameter that allows you to send the selected value to the url specified in the field. It is worth noting that this functionality in Joomla has been gradually developing for quite a long time. However, a separate universal field type that can be used for your needs appeared only in Joomla 5. It's not even in Joomla 4.
Previously, this constructor was called JForm. I will assume that not all my readers have in their hands such a development tool as an IDE - development environment - a la PHP Storm or VS Code, so I will try to give additional guidelines for navigating the code base.
In Joomla, the Logic is separated from the View (the actual HTML output), so we will explore it in several places at the same time.
Logic is the Form class. In Joomla 5, the Form class files are located in libraries/src/Form. We examine these files in order to understand the logic itself, what happens to the data and how to work with it.
In short, the Form constructor receives XML with a description of the fields. reads data (field type, custom field class from the addfieldprefix attribute, if any, etc.), loads the required field class using FormHelper. If the field has some rules for filtering the output data - the FormRule class is used - remember the Joomla fields of the filelist type, where you can specify filtering parameters and select, for example, only php or only css files.
Joomla Form field class files are located in libraries/src/Form/Field. There are, to put it mildly, a lot of them. This is the building material of the admin panel, and sometimes the frontend too.
Class files describe class properties such as $type, $layout, and others necessary for operation. Most fields have methods getInput() - actually returns the HTML output of the field, getLayoutData() - preprocessing data for the field before sending it to the render, getLabel() - working with the field label, etc.
We remember that the field classes inherit the parent FormField class. In the class file libraries/src/Form/FormField.php the possible attributes of the field are described, that can be used in the description in XML. They have a brief description of what it is and why.
Child classes (heirs) have the ability to work with the methods of the parent class and, if necessary, override it.
Each field class has a HTML output. In classic MVC, the View works with data output immediately, but in Joomla there is an additional layer - Layout, which allows you to override layouts - one of the most important features of this CMS. The core layouts are expected to be located in the layouts folder in the site root. They pass an array of $displayData with all the data received from the getLayoutData() method. We specify which output layout to use in the $layout class property.
<?php /** * Name of the layout being used to render the field * * @var string * @since 3.7 */ protected $layout = 'joomla.form.field.email';
This type of recording is quite common. In Joomla, layout is a dot-separated path to the layout file from the layouts folder at the root of the site. That is, the entry $layout = 'joomla.form.field.email' means that layouts will be used when rendering the field layouts/joomla/form/field/email.php.
<?php use Joomla\CMS\Layout\LayoutHelper; $displayData = [ 'src' => $this->item->image, 'alt' => $this->item->name, ]; echo LayoutHelper::render( 'joomla.html.image', $displayData );
Similarly, this example will use layout layouts/joomla/html/image.php. Some layouts can be overridden in the html folder of site templates and admin panel.
Accordingly, if we want to see exactly what data comes to the layout in the end and how it is displayed, go to the layout file and look.
Now let's return to the main task of the article.
Examples are important for us to study (Joomla 5.0.1 at the time of writing this article):
The single contact modal select field from com_contacts at the time of writing this article has not yet been converted to a universal field type one and just lies in (in Joomla 5.0.2, when this article was written) administrator/components/com_contact/src/Field/Modal/ContactField.php. It inherits FormField directly, not ModalSelectField.
The algorithm of actions for adding your own field is as follows:
<?php /** * Name of the layout being used to render the field * * @var string * @since 3.7 */ protected $layout = 'joomla.form.field.email';
In order for everything that happens in PHP to be clear, you need to first look at the layout of the field output. It is in the file layouts/joomla/form/field/modal-select.php. In fact, 2 input fields are output - one visible, the other invisible. The title of the selected article, contact, or product is entered in the visible field in the form of a placeholder - the $valueTitle parameter. And the second is his id - $value. If we have not selected anything yet, there should be a phrase in the field like "select an article" or "select a product". This is a language constant that we put in the hint attribute in the XML field or in the setup() method of the field class.
All parameters available for the output layout (which means those that can be used programmatically or in an XML file):
<?php /** * Name of the layout being used to render the field * * @var string * @since 3.7 */ protected $layout = 'joomla.form.field.email';
The field class, as you may have guessed, is in my plugin. The way to it plugins/wtproductbuilder/providerjoomshopping/src/Field/ProductlistField.php. I took the single modal article select field as a basis and redesigned it to suit my needs - choosing a product from the JoomShopping online store. We extend the parent ModalSelectField class with our own class.
My tasks include only product selection, editing and creation are not, so in the text of the article we are talking only about product selection. The PHP class is small, I will give it in its entirety and comment on it.
<?php use Joomla\CMS\Layout\LayoutHelper; $displayData = [ 'src' => $this->item->image, 'alt' => $this->item->name, ]; echo LayoutHelper::render( 'joomla.html.image', $displayData );
Separately, the getValueTitle() method was introduced, which shows the name of the selected entity (product name, article title, etc.) in cases when they have already been selected and saved. That is, we went to edit the menu item, we do not touch the field, but we want to see the title of the article / product name understandable to people, and not just an id. This method shows the desired title.
<field type="productlist" name="product_id" addfieldprefix="Joomla\Plugin\Wtproductbuilder\Providerjoomshopping\Field" label="Field label" hint="Field placeholder" />
In some fields where more complex functionality is required - multilingual associations and so on - there are other methods in the field class that override the basic methods of the FormField class:
In our case, there is no such need, so we do not use them.
When you click on the "select" button, a modal Bootstrap window opens, in which a list of products opens in the
In my plugin, the onAjaxProviderjoomshopping() method returns the HTML output of the list of products. There we loop through the array with them, take the picture, the name and output. The code is generally voluminous, so I will publish the most important fragments.
Simplified loop code example:
<?php extract($displayData); /** * Layout variables * ----------------- * @var string $autocomplete Autocomplete attribute for the field. * @var boolean $autofocus Is autofocus enabled? * @var string $class Classes for the input. * @var string $description Description of the field. * @var boolean $disabled Is this field disabled? * @var string $group Group the field belongs to. <fields> section in form XML. * @var boolean $hidden Is this field hidden in the form? * @var string $hint Placeholder for the field. * @var string $id DOM id of the field. * @var string $label Label of the field. * @var string $labelclass Classes to apply to the label. * @var boolean $multiple Does this field support multiple values? * @var string $name Name of the input field. * @var string $onchange Onchange attribute for the field. * @var string $onclick Onclick attribute for the field. * @var string $pattern Pattern (Reg Ex) of value of the form field. * @var boolean $readonly Is this field read only? * @var boolean $repeat Allows extensions to duplicate elements. * @var boolean $required Is this field required? * @var integer $size Size attribute of the input. * @var boolean $spellcheck Spellcheck state for the form field. * @var string $validate Validation rules to apply. * @var string $value Value attribute of the field. * @var string $dataAttribute Miscellaneous data attributes preprocessed for HTML output * @var array $dataAttributes Miscellaneous data attribute for eg, data-* * @var string $valueTitle * @var array $canDo * @var string[] $urls * @var string[] $modalTitles * @var string[] $buttonIcons */
Second. The link tag code must contain data attributes with the data we need. We saw this fragment in the sample code of the goods output cycle.
<?php /** * Name of the layout being used to render the field * * @var string * @since 3.7 */ protected $layout = 'joomla.form.field.email';
Now let's start working with JavaScript. In the process of writing the article, nuances emerged that allow us to talk about the old and new ways of working.
We remember that in the process of working, we connected the following js scripts
Let's start with our own javascript. Here, using the select-link class, we get all the selectors and hang the listener of the click event on them.
<?php use Joomla\CMS\Layout\LayoutHelper; $displayData = [ 'src' => $this->item->image, 'alt' => $this->item->name, ]; echo LayoutHelper::render( 'joomla.html.image', $displayData );
If everything is intuitive with id and title, then with the data object and postMessage, it may not be obvious to those who are used to working with Joomla.
Previously, in Joomla 2.5, 3.x and even in 4.x, the following approach was used: in the layout of the field output, we used an inline script to hang a handler function on the window, and from
<field type="productlist" name="product_id" addfieldprefix="Joomla\Plugin\Wtproductbuilder\Providerjoomshopping\Field" label="Field label" hint="Field placeholder" />
In this form, the function name was specified in the data-function attribute of each link in the list of articles / contacts / menu items. And the function itself was placed inline, sometimes unifying its name with an additional id. For example, "jSelectArticle_".$this->id.
The jSelectArticle() function or similar (we would have jSelectProduct()) is a wrapper for the standard processModalSelect() function from the file modal-fields.min.js . It, in turn, calls the processModalParent() function and closes the modal window after execution.
This function needed to specify a bunch of parameters to work: the type of entity (article, contact, etc.), the prefix of the field (which in practice turned out to be the id of the HTML field selector), the actual id and title - the parameters we need, etc.
In one function, everything was collected for all occasions. That's where the data was placed in our field.
However, now, in Joomla 5, this file is no longer needed. If we use the standard layout of the field output, then the modal-content-select-field asset is connected to it, working in a new way.
Now the Joomla 5 frontend is switching to using JavaScript postMessages. Since not all old extensions are yet ready to switch to new rails, the JoomlaExpectingPostMessage flag has been implemented, which allows you to distinguish outdated event calling methods. It has an indirect relation to the described method of work, but it may be useful to someone. This flag will be removed after the full transition to postMessages.
So, now we don't need extra attributes of links with the name of the called functions. Instead, we use the postMessage mechanism. To do this, in the data object, we need to specify the messageType parameter equal to joomla:content-select. Why? From the point of view of JavaScript, working in Joomla is as follows:
In the process of studying the Joomla core code and searching for a solution, I naturally came across the functions jSelectArticle() and the like. Then I came across postMessage and decided to make my MessageType by giving it a long unique name. To make it work, I wrote my own processing to it, calling the (as it turned out, outdated) processModalSelect() function. And I was faced with the fact that the modal window did not want to close in any way, although the data was inserted correctly into the fields. Further searches led first to the correct type of event, and then to the removal of unnecessary scripts and simplification of the code as a whole.
Joomla provides the developer with a rich set of tools for working with and obtaining data from third-party sources and using it in your code. Working with JForm fields is important for a developer when creating their own extensions, especially when it is necessary to solve a task that goes beyond typical scope. Of course, such a modal window and the selection of data in it is a rather special case, but in this way you can both override any other JForm fields and create your own types with your own UX logic.
The above is the detailed content of Creating a custom Form field type in Joomla sing the Modal Select example. For more information, please follow other related articles on the PHP Chinese website!