alhimik1986 / yii2_crud_module
出色的yii2 Gii CRUD代码生成器,用于创建ajax应用程序。
Requires
- php: >=5.4.0
- alhimik1986/yii2_js_view_module: ^1.0
This package is auto-updated.
Last update: 2024-08-29 04:19:57 UTC
README
出色的Gii CRUD模块,用于生成基于Yii2框架的单页ajax应用程序代码。
演示: http://tfb7950x.bget.ru/application/web/index.php?r=film
特性
- 使用ajax方法添加、读取、删除、更新记录,无需重新加载页面
- 可以批量删除记录
- 使用ajax而不是pjax(甚至支持IE8)
- 有分页器,可以设置每页显示的记录数(Gii的所有扩展中都没有这项功能)
- 可以同时按多个列排序,例如,先按职位排序,然后按姓氏对每个组进行排序
- 可以按关联表排序(下面将演示如何操作)
- 在文本字段中搜索时不需要按Enter键,当用户停止输入时自动启动搜索
- 有快捷键(Insert、Ctrl+Enter、Ctrl+Delete、Esc,分别:添加、保存、删除、取消)
- Esc键可以清除搜索文本框(虽然很小,但仍然让人感到愉悦)
- 直接从服务器输出验证错误,而不是从客户端脚本输出(即可以通过ajax输出错误,例如,关于错误密码等)
- 如果数据不符合指定格式,则在屏幕上输出数据(通常是服务器内部错误,如果不这样做,则错误可能根本不会被注意到,即使注意到了,也必须打开调试器)
- 易于学习,生成的代码易于用于创建ajax页面。
限制
- 当使用jQuery 3及以上版本时,触摸屏(移动设备)上的表单移动将停止工作。因此,建议使用jQuery 1或2。
待办事项
- 添加在表格内部显示详细信息的功能(如这里的“展开”按钮:http://demos.krajee.com/grid-demo)
- 实现导出为html、csv、text、excel、pdf、json
安装
使用composer下载。在应用程序文件夹中的composer.json文件中添加以下行
"require": {
"alhimik1986/yii2_crud_module": "^1.0"
},
或在命令行中输入
$ composer require alhimik1986/yii2_crud_module
然后在config/web.php文件中添加以下行
// Добавляю генератор кода ajax_form_crud if (YII_ENV_DEV) { $config['modules']['gii']['generators']['ajax_form_crud_generator'] = [ 'class' => 'alhimik1986\yii2_crud_module\generators\crud\Generator', 'templates' => [ 'ajax_form_template' => '@vendor/alhimik1986/yii2_crud_module/generators/crud/default', ], ]; }
访问地址: https:///index.php?r=gii 或 https:///gii 。然后点击“AjaxForm CRUD Generator”链接。
生成的代码的扩展使用
ajax-form.js库的哲学
让我们看看文件views/@conroller_id/index/_js_table.php。我们看到
new ajaxForm({
...
});
所以,这个“类实例”传递了参数。这些参数覆盖了默认参数。默认参数可以在ajax-form.js库中看到,每个参数的用途在注释中指明。传递给这个类实例的值覆盖了默认参数,并放在“settings”变量中。经常使用“settings”变量,并将其作为参数传递给许多函数。顺便说一下,默认参数包含了ajax-form.js库的所有系统功能,因此,通过传递参数给实例可以完全改变这个库的行为。
为了让大家明白其结构,我将介绍这个库的哲学。
让我们假设如果我们手动使用jQuery实现CRUD会怎样工作
- 需要指定选择器和触发表单出现的事件。在本例中,这是“添加”按钮(.ajax-form-button-create)和“click”事件。
- 事件触发时,需要发送ajax请求以获取表单内容并将该表单输出到特定位置。
- 获取到的表单需要设置为中心屏幕位置,使其可移动和可拉伸(处理表单1)。
- 获取到的表单需要绑定“表单数据提交按钮”和“取消”按钮的事件(处理表单2)。
- 当触发表单数据提交事件时,需要发送表单并获取一个结果(内部服务器错误、验证错误或成功结果)。
- 在成功结果的情况下,需要删除表单并发送ajax请求以更新表格。
为此,我们需要3个带有回调函数的ajax请求,这些回调函数仅在成功结果的情况下依次调用。但由于我们还需要传递参数(例如,按钮选择器、请求url等),因此我们将它们封装在3个相应的对象中。
- 用于显示表单的名称为create。
- 用于提交表单的名称为submit。
- 用于在成功提交表单后更新表格的名称为afterSubmit。
在代码中,它们将如下所示。
new ajaxForm({
create: {
...
},
submit: {
...
},
afterSubmit: {
...
},
});
ajaxForm()类中传递的对象的说明。
create对象。
每个对象将包含一些字段,让我们来考虑一下可能有哪些。我们需要指定触发ajax请求的条件,通常这是点击按钮。因此,我们需要指定选择器(例如,.ajax-form-button-create)和事件类型(通常为“click”)。此外,如果愿意,可以指定委托者,但默认值为document,因此如果未指定,则不会发生任何问题。因此,字段将具有以下名称:“delegator”,“selector”,“on”——分别代表委托者选择器和事件,在jQuery中它们将如下所示
$(delegator).on(on, selector, function(){
});
当条件满足时,将执行ajax请求,因此我们还需要指定此请求的参数。这些参数在“ajax”字段中设置。参数名称与常规jQuery方法$.ajax({})中的参数名称相同。但为了增加灵活性,在“ajax”字段中需要传递一个函数,该函数返回一个对象。如果函数返回值为false,则不会执行ajax请求,从而也不会执行后续链(submit和afterSubmit)。在代码中将大致如下所示
new ajaxForm({
create: {
delegator: document,
selector: '.ajax-form-button-create',
on: 'click',
ajax: function(settings) {
return {
url: 'https:///controller_id/form'
};
}
},
submit: {
...
},
afterSubmit: {
...
},
});
其中settings,如前所述,是传递参数和默认参数的混合。即,我们可以在回调函数中使用在ajaxForm中传递的所有内容。换句话说,通过变量settings,我们可以访问任何参数。例如,settings.create.selector - 我们设置的选择器。要访问触发函数调用的元素,它位于settings.create.$中。正如我们所理解的,我们可以像操作普通jQuery元素一样操作它,例如,settings.create.$.css({color: 'green'});
。
在成功请求的情况下,将调用回调函数“success”,它具有data和settings参数,其中data是接收到的数据。应注意的是,data只包含响应部分中的字段content的值。响应部分的格式将在下面描述。
return $($(data)).appendTo('<?=$wrapper_selector?>');
还应注意的是,success方法必须返回接收到的表单的jQuery对象。接下来,此对象将包含在settings.form.$中,它用于内部处理(例如,定位在屏幕中心,使表单可移动,绑定点击“保存”、“取消”、“关闭”按钮的事件等)。
在success方法之后,将调用afterSubmit方法。它用于处理表单的后续操作,例如,我们希望使用select2.js插件初始化我们的表单中的下拉列表,而文本区域(textarea)则使用WYSIWYG编辑器。代码示例
new ajaxForm({
create: {
...
afterSuccess: function(settings){
var $form = settings.form.$;
$form.find('select').select2();
$form.find('textarea').froalaEditor();
}
},
submit: {
...
},
afterSubmit: {
...
},
});
如果我们不想使我们的表单可移动和可拉伸,则需要将_methodForm()方法重写为空函数。示例
new ajaxForm({
create: {
...
_handleForm: function(){},
},
submit: {
...
},
afterSubmit: {
...
},
});
同样,您也可以重写任何其他系统功能:_success、_afterSuccess 等。要了解更多关于这些函数的作用,请查看 ajax-form.js 文件。
submit 对象
submit 对象具有大致相同的“字段”和“方法”
new ajaxForm({
create: {
...
},
submit: {
// delegator: document, // Задать делегатор нельзя, делегатором является форма
selector: '.ajax-form-button-submit, .ajax-form-button-delete', // селектор кнопок, по нажатию которых происходит отправка данных формы
ajax: function(settings) {
var $form = settings.submit.$.parents('form');
// Если нажата кнопка "Удалить", то спрашивать подтверждение
if ( settings.submit.$.hasClass('ajax-form-button-delete')) {
if ( ! confirm('Удалить эту запись безвозвратно?'); ?>'))
return false; // отправка данных не произойдет
}
var $_return = {};
var url = $form.attr('action');
var data = $form.serializeArray();
// Если была нажата кнопка "Удалить", то меняем адрес и параметры запроса на те, которые удалят эту запись
if ( settings.submit.$.hasClass('ajax-form-button-delete')) {
url = <?= Url::to(['delete']); ?>';
data = {
<?= $className; ?>: {
id: settings.create.$.attr('data_id')
}
};
}
$_return['url'] = url;
$_return['data'] = data;
$_return['type'] = 'post';
return $_return;
}
},
afterSubmit: {
...
},
});
如果点击了“保存”按钮,则替换一个地址和参数,如果点击了“删除”按钮,则替换其他地址和请求参数。
还有以下方法:notValid(data, settings) - 在验证出错时调用,error(xhr, settings) - 在服务器内部出错时调用。它们对应相应的系统方法:_notValid(data, settings) 和 _error(xhr, exception)。因此,如果我们想禁用验证错误或服务器内部错误的输出,以下是一个示例代码
new ajaxForm({
submit: {
...
_notValid: function(){}, // отключаю вывод ошибок валидации
_error: function(){}, // отключаю вывод внутренней ошибки сервера
},
});
如果我们需要只在第一个遇到的字段上显示验证错误,建议使用以下代码
// Эффект тряски и навести фокус на указанный элемент
window.shakeAndFocus = function($elem) {
if ($elem.length > 0) {
$('html, body').stop().animate({scrollTop: $elem.offset().top - 90}, 200, function(){
<?php if ($this->isMobileOrTablet()): ?>
$elem.focus().shake(3, 5, 100);
<?php else: ?>
$elem.focus();
<?php endIf; ?>
});
}
};
new ajaxForm({
submit: {
...
notValid: function(data, settings){
var $form = settings.create.$.parents('form');
$form.find('.error:not(:first)').parent().html('');
$form.find('.input-error:not(:first)').removeClass('input-error');
$form.find('.label-error:not(:first)').removeClass('label-error');
$form.find('.has-error').removeClass('has-error');
// Получаю самое первое поле с ошибкой
var i, j, k, id;
for(i in data) {
for(j in data[i]) {
for(k in data[i][j]) {
id = i+'_'+j;
break;
}
break;
}
break;
}
var $input = $form.find('#'+id).first();
window.shakeAndFocus($input);
},
},
});
afterSubmit 对象
在 afterSubmit 对象中使用 fewer 参数。它仅在提交成功后调用。
new ajaxForm({
create: {
...
_handleForm: function(){},
},
submit: {
...
},
afterSubmit: {
ajax: function(settings) {
$(settings.form.selector).remove(); // Закрываю форму только после удачной записи и обновлении таблицы
$('<?=$table_id; ?>').trigger('search'); // Обновляю таблицу (поиск в таблице)
return false; // Не делать ajax-запрос, т.к. форма обновляется вызовом триггера "search"
},
success: function(data, settings) {}
},
});
按照逻辑,我们应该使用给定的地址和参数执行 ajax-请求以更新表格。但有一个更简单、更正确的方法:我们需要重新在表格中启动搜索,而不需要发送任何 ajax-请求。执行表格搜索的脚本位于模板 @vendor/alhimik1986/yii2_js_view_module/views/jsPlugins/_ajaxTable.php 中。如果在某个时刻需要启动表格搜索,则在该表格中启动 'search' 触发器。
$('#table_id').trigger('search');
ajaxForm 的其他对象
如果您不使用 ActiveForm 并且启用了 enableCsrfValidation,则服务器可能会抱怨没有传递 csrf-令牌。为了避免这种情况,您可以在 ajaxForm 中传递这些令牌。
我们经常需要看到数据上传或服务器处理数据的过程。为此,我们需要一个加载指示器,它在发送 ajax-请求时出现,并在请求完成后消失。在 _js_table.php 模板中,我们指定需要放置该指示器的元素(loadingElem),并设置该指示器的 CSS 样式(loadingStyle)。总的来说,我们的其他 ajaxForm 对象看起来大致如下
new ajaxForm({
loadingElem: loadingElem,
loadingStyle: loadingStyle,
csrf: csrf,
create: {
...
_handleForm: function(){},
},
submit: {
...
},
afterSubmit: {
...
},
});
服务器对 ajax-请求的响应格式
在 ajax-请求中,服务器应使用 JSON 格式生成响应。该对象应包含以下部分
{
status: 'success' | 'error', // статус ответа (success - результат успешный и цепочка вызовов будет продолжена, error - ошибка валидации)
content: 'text', // Содержимое ответа, которое передедается в аргумент data.
message: '', // flash-сообщения, которые используется в yii-фреймворке и задаются таким образом: Yii::$app->session->setFlash('success', 'Сохранено успешно!')
}
为了避免处理格式,有一个名为 alhimik1986\yii2_crud_module\web\JsonController 的类,它继承自 yii\web\Controller。其中已经内置了用于生成响应的必要方法。我们可以在生成的控制器中看到实现示例。示例
return $this->renderJson('view_name', ['model' => $model]); // Тоже самое, что и $this->renderPartial('view_name', ['model'=>$model]), только в нужном формате для ajax-form.js. {status: 'success', content: 'содержимое вьюшки', message: ''}
return $this->checkErrorsAndDisplayResult($model); // Делает всю грязную работу: проверяет модель на наличие ошибок валидации и, если они есть, выводит их в нужном формате; если ошибок нет, то выводит {status: 'success', content: 'ok', message: ''}
如果模型包含验证错误,则 ajax-form.js 将找到包含错误的字段,并在父元素 (.form-group .field-modelName-fieldName) 中添加 .has-error 类。如果表单中不存在父类 (.form-group .field-modelName-fieldName),则为了安全起见,ajax-form.js 在文本字段中添加 .input-error 类,在其标签 (label) 中添加 .label-error 类,但为了使它们用红色突出显示,需要在 CSS 中添加 .input-error, .label-error {color: #a94442;}
如果服务器的响应不符合指定的格式(例如,在服务器内部出错时),则 ajax-form.js 将在弹窗中输出它接收到的所有内容,即输出屏幕上的整个错误文本。
在同一页面上使用多个 crud
是的,有这样的可能性。为此,需要为每个 crud 分别生成。然后需要将 index.php 模板的内容合并到一个,并将两个 crud 的 _js_table.php 和 _js_plugins.php 包含进来。然后,在 _js_table.php 模板中,需要找到生成 URL 地址的方法:Url::to(['create'])
并将相应的控制器添加到地址中,例如,Url::to(['/myController/create'])
。
请记住,这些 crud 不会相互干扰,因为它们位于不同的 $wrapper_selector
(请参阅 _js_table.php)上,即不同的具有不同 id 的标签。请记住,一个 crud 的表单不会删除另一个 crud 的表单,因为它们的表单具有唯一的 id,并且在 ajaxForm 中进行了指定。
new ajaxForm({
form: {
selector: '#<?= $className; ?>-ajax-form',
},
create: {
...
},
submit: {
...
},
afterSubmit: {
...
},
});