It is no secret that the lion's share of the functionality of corporate (and not only) applications are
CRUD operations with simple validation and business logic. For many datasets, when working with them, it’s convenient to use a table view; for this, quite powerful tools can be used, such as jqGrid, DataTables, Handsontable, or simpler ones like the
Yrid2 GridView widget. It copes well with the task of managing small datasets that do not require complex search and sorting methods, complies with the principles of
RAD , but has several drawbacks and obvious points for improvement. Consider a few of these problems and solutions.
1. For any actions with data that cause a change in the state of the table, a full page reload occurs. This is solved by a
wiki method using
Pjax , which is integrated into Yii2. Enough to wrap the GridView in
<?php Pjax::begin(['id' => 'grid-pjax']); ?> <?php Pjax::end(); ?>
and the procedures for deleting, filtering, sorting, navigating through pages will occur without a full refresh of the page; GridView itself already integrates Pjax support in the required amount.
However, in programming it is often necessary to compromise between convenience (use, support, debugging, etc.) and complexity, also in this case, using Pjax is simple and convenient, but when updating a part of the page with its help, the server still generates the full version of the page from which Pjax cuts only the necessary one on the client side. But it's easy to fix by adding something like
if (Yii::$app->request->isPjax) { return $this->renderPartial('index', [
2. Only updating without reloading the page after saving the form will not work, in this case you can use the mentioned method from the wiki by placing the form on the same page with the GridView, and wrapping it in Pjax as well. Or use the
modal windows , the latter will be discussed further and will go. Since it turned out that Yii2 is closely related to Bootstrap, and it is used in many projects on this framework, then you can use modal windows from Bootstrap. For these purposes, you can use the extension
yii2-bootstrap , and from it the Modal widget.
Add the Modal widget to the page source code, for example, like this:
<?php Modal::begin(['id' => 'form-modal']); ?> <?php Modal::end(); ?>
When clicking on the button for adding a new record or editing, we display the form in a modal window:
const modal = $("form-modal"); $("div.modal-body", modal).load("url___"); modal.modal("show");
Next, we set the event interceptor of the beforeSubmit form (remembering to return false at the end), in which we send the contents of the form using
AJAX to the server, if everything suits us in the response received from the server, then we hide the form and reboot Pjax; data in the same modal window, or perform some other action:
modal.on("beforeSubmit", "form", function () { const form = $(this); $.ajax({ type: "POST", url: form.attr("action"), data: new FormData(form[0]), processData: false, contentType: false, success: function (message) { if (message) { $(".modal-body", modal).html(message); return; } modal.modal("hide"); $.pjax.reload({container: "#grid-pjax"}); } }); return false; });
With the described approach, if the id loaded into the modal window of the form is not unique within the page, then there may be problems with validation and generally correct functioning of the form. And this can happen, because the widget's id's automatically set by the framework are automatically numbered in order, and when an AJAX request is made to the server, this numbering will start from the beginning, from scratch. To solve a problem, you can always set the form id manually, or in the onClick event interceptor you can use the form submission buttons
const form = $("form", modal); if (form.attr("id") === "w0") { form.attr("id", widgetId + "-modal-form"); form.yiiActiveForm(); }
')
3. Appetite comes with eating, and now I would also like to send a certain message to the user (already hiding the form and closing the modal window), a file, and can, despite all the principles of AJAX, still refresh the page or make a switch to another. Unlinking from the standard form submission procedure in the previous paragraph, this can be easily implemented in the successor handler of the $ .ajax method described above.
if (message === "#reload") { window.location.href = window.location.href.replace("#", ""); } else if (message.substring(0, 10) === "#redirect ") { window.location.href = message.substring(10); }
You can also ask the user any question, request confirmation of actions, and, depending on the answer, send a request to the server or not.
All this (and even more) was implemented as a
yii2-gridview-ajaxed-widget extension , in which the modified GridView widget (inherited from the GridView framework) can be directly used as a replacement for the standard one. In this modified widget, some optional parameters appear that are associated with additional functionality, for example, addButtons, where you can specify one or more buttons that open the form for adding a new element, each can be added with its route, you can also specify your own route for the built-in update buttons , view, delete, but more often than not, the widget itself determines the desired route and the names of the key fields of the model and forms the necessary GET parameters. You can also specify your callback functions for handling errors and displaying a message to the user, and a little bit of any different different customization, the need for which arose in the course of working on various projects.
If the widget itself can be used without changes, as standard, then the controller will need to make some changes, for example, the actions of the update and removal procedures should contain something like this code:
if ($model->load(Yii::$app->request->post()) && $model->save()) { return null; } return $this->renderAjax('_form', [ 'model' => $model, ]);
Delete, may not return anything at all, or return something like “#alert Record cannot be deleted!”, Then the corresponding message will be displayed to the user. As you see, create.php and update.php are no longer needed, the application code is simplified, and the possibilities are somewhat extended.
It also becomes possible to use several independent GridViews on one page, for example, as nested form elements that are independent from each other, without form dependencies on them, but dependent on the form itself:
Some points in the presented code can be simplified if the form is small and special optimization is not required.
Anticipating questions for a large number of widget parameters (like readOnly, actionColumnLeft) or the fix for
Select2 contained in it, or support for the
spinner from Font Awesome. I can say that this does not interfere, given the small amount of code and the absence of unforeseen effects; these libraries are widely used in many projects on Yii2; This is a RAD development widget. And parameters like actionColumnTemplate are needed because of adding functionality to the widget that is important for the assigned mission, no one bothers to set actionColumnEnabled to false and add your own ActionColumn by examining the corresponding part of the widget code. And also add your own buttons with various actions, like downloading a file and sending an AJAX request to the server without changing the state of the GridView.
Also, it is known that Pjax will be removed from the Yii core in the third version of the framework, but for now it is convenient to use there. With the release of Yii3, the widget code can be completely rewritten in the realities of the new version of the framework, or even abandon Pjax and write the necessary functionality using other libraries or plain JS, you can also say about jQuery and Bootstrap.
As usual, any constructive criticism, questions and suggestions are welcome.