Yii2 在 yii2-formwizard 的表格步骤中使用 Select2
Yii2 Using Select2 with tabular step of yii2-formwizard
我正在使用 yii2-formwizard,这是我使用 kartik\select2
的项目中的一个方便工具。一切正常,除非我按下添加以获取下一组 select2
上一组的下拉列表消失了。
当我修改我的控制器以从我的模型捕获数据时发生这种情况,如我之前 所述,我在脚本方面遗漏了一些东西我在 jquery/JS 等方面有点差,无论如何,除了正在保存数据并且小部件工作正常
我的控制器
<?php
public function actionCreatemulti()
{
$this->layout = 'layout2';
$model = [new Todelete()];
$sex = [['id' => 1, 'name' => 'male'], ['id' => 2, 'name' => 'female']];
if (Yii::$app->request->isPost) {
$count = count(Yii::$app->request->post('Todelete', []));
//start the loop from 1 rather than 0 and use the $count for limit
for ($i = 1; $i < $count; $i++) {
$model[] = new Todelete();
}
if (Model::loadMultiple($model, Yii::$app->request->post()) && Model::validateMultiple($model)) {
foreach ($model as $md) {
$md->save(false);
}
return $this->render('index');
}
}
return $this->render('create', [
'model' => $model,
'sex' => $sex
]);
}
我的观点
echo FormWizard::widget(
[
'formOptions' => [
'id' => 'my_form_tabular'
],
'steps' => [
[
//should be a single model or array of Activerecord model objects but for a single model only see wiki on github
'model' => $model,
//set step type to tabular
'type' => FormWizard::STEP_TYPE_TABULAR,
'fieldConfig' => [
'sex' => [
'widget' => Select2::class,
'containerOptions' => [
'class' => 'form-group'
],
'options' => [
'data' => $data,
'options' => [
'class' => 'form-control'
],
'theme' => Select2::THEME_BOOTSTRAP,
'pluginOptions' => [
'allowClear' => true,
'placeholder' => 'Select sex'
]
],
//set tabular events for select2 fix which doesnot work correctly after cloning
'tabularEvents' => [
'beforeClone' => "function(event, params){
//fix for select2 destroy the plugin
let element = $(this);
element.select2('destroy');
}",
"afterClone" => "function(event, params){
//bind select2 again after clone
let element = $(this);
let elementId = $(this).attr('id');
let dataKrajee = eval(element.data('krajee-select2'));
let dataSelect2Options = element.data('s2-options');
$.when(element.select2(dataKrajee)).done(initS2Loading(elementId, dataSelect2Options));
}",
"afterInsert" => "function(event,params){
//initialize the options for the select2 after initializing
//changed according to my environment
let selectElement = $(this).find('.field-todelete-'+params.rowIndex+'-sex > select');
let dataKrajee = eval(selectElement.data('krajee-select2'));
selectElement.select2(dataKrajee);
}"
]
]
]
]
]
]
);
https://cdn1.imggmi.com/uploads/2019/8/31/158dc0f338e0d780747c5f72fa2ed6bb-full.png https://cdn1.imggmi.com/uploads/2019/8/31/4e394e87aa162d3f457c32af8d30373b-full.png
原因
您指出的问题确实存在,您是对的。但这个问题与最近对 kartik\select2 @V2.1.4
的更改有关。演示链接使用的是 select2 V2.1.3
的旧版本,其中没有定义此 dataset
属性,因此可以正常工作。
小部件未集成所有这些更改,并留给了正在集成小部件的用户
The reason is that it won't be possible to control it correctly inside
the plugin as there could be any widget a user wants to use and going
to keep adding the code for every other widget isn't what I would vote
for. So a better approach would be to provide the event triggers for
the specific actions which require a pre or post-processing of an
element, where according to the needs the user can adjust his code
疑难解答
关于这个问题,有一个新的数据集属性 data-select2-id
,它包含 select2 绑定到的输入的名称,并且克隆新元素后,该属性未更新为较新的元素 ID,这导致旧的 select 元素消失。
见下图,它来自我自己的代码,所以请忽略 address-0-city
字段名称,因为它与您的代码无关,仅供理解
解决方案
所以我们需要将afterInsert
事件中的代码改成下面的代码
let selectElement = $(this).find('.field-todelete-'+params.rowIndex+'-sex > select');
let dataKrajee = eval(selectElement.data('krajee-select2'));
//update the dataset attribute to the
if (typeof selectElement[0].dataset.select2Id !== 'undefined') {
//get the old dataset which has the old id of the input the select2 is bind to
let oldDataSelect2Id = selectElement[0].dataset.select2Id;
//delete the old dataset
delete selectElement[0].dataset.select2Id;
//add the new dataselect pointing to the new id of the cloned element
let newDataSelect2Id = oldDataSelect2Id.replace(
/\-([\d]+)\-/,
'-' + parseInt(params.rowIndex) + '-'
);
//add the new dataset with the new cloned input id
selectElement[0].dataset.select2Id= newDataSelect2Id;
}
selectElement.select2(dataKrajee);
我会在接下来的几天更新 wiki 文档上的代码和代码示例以及演示。
希望对您有所帮助。
这通常发生在使用小部件的 ID 发生冲突时。
通过检查 HTML 页面来确认这没有发生。
特别注意这些部分(此代码只是示例):
<Block1>
<select id = "todelete-0-sex">
</Block1>
<Block2>
<select id = "todelete-1-sex">
</Block2>
<Script>
// ...
$("# Todelete-0-sex").select2({...});
// ...
$("#Todelete-1-sex").select2({...});
// ...
</Script>
我已经在全新安装的 Yii2 (2.0.25) 上复制了您的代码,使用以下两个组件:
- buttflattery/yii2-formwizard (1.4.6)
- kartik-v/yii2-widget-select2 (v2.1.3)
进行一些与使代码正常工作无关的小改动,一切似乎都正常。
回顾
- 验证创建两者时没有冲突
小部件
- 检查 "yii2-formwizard" 和 "yii2-widget-select2" 组件的版本
MyController.php(控制器)
...
public function actionTest()
{
//$this->layout = 'layout2';
$model = [new Todelete(['id' => 1, 'name' => 'a', 'sex' => 'male']), new Todelete(['id' => 2, 'name' => 'b', 'sex' => 'male']), new Todelete(['id' => 3, 'name' => 'c', 'sex' => 'female'])];
$sex = [['id' => 1, 'name' => 'male'], ['id' => 2, 'name' => 'female']];
if (Yii::$app->request->isPost) {
$count = count(Yii::$app->request->post('Todelete', []));
//start the loop from 1 rather than 0 and use the $count for limit
for ($i = 1; $i < $count; $i++) {
$model[] = new Todelete();
}
if (Model::loadMultiple($model, Yii::$app->request->post()) && Model::validateMultiple($model)) {
foreach ($model as $md) {
$md->save(false);
}
return $this->render('index');
}
}
return $this->render('test', [
'model' => $model,
'sex' => $sex
]);
}
...
Todelete.php(型号)
...
use yii\base\Model; // NOTE: in your case your model will most likely extend ActiveRecord instead of Model class
class Todelete extends Model
{
public $id;
public $name;
public $sex;
/**
* @inheritdoc
*/
public function rules()
{
return [
['id', 'integer'],
[['sex', 'name'], 'string'],
];
}
}
...
create.php(查看)
use kartik\select2\Select2;
use \buttflattery\formwizard\FormWizard;
echo FormWizard::widget(
[
'formOptions' => [
'id' => 'my_form_tabular'
],
'steps' => [
[
//should be a single model or array of Activerecord model objects but for a single model only see wiki on github
'model' => $model,
//set step type to tabular
'type' => FormWizard::STEP_TYPE_TABULAR,
'fieldConfig' => [
'sex' => [
'widget' => Select2::class,
'containerOptions' => [
'class' => 'form-group'
],
'options' => [
//'data' => $data,
'options' => [
'class' => 'form-control'
],
'theme' => Select2::THEME_BOOTSTRAP,
'pluginOptions' => [
'allowClear' => true,
'placeholder' => 'Select sex'
]
],
//set tabular events for select2 fix which doesnot work correctly after cloning
]
]
]
]
]
);
我正在使用 yii2-formwizard,这是我使用 kartik\select2
的项目中的一个方便工具。一切正常,除非我按下添加以获取下一组 select2
上一组的下拉列表消失了。
当我修改我的控制器以从我的模型捕获数据时发生这种情况,如我之前
我的控制器
<?php
public function actionCreatemulti()
{
$this->layout = 'layout2';
$model = [new Todelete()];
$sex = [['id' => 1, 'name' => 'male'], ['id' => 2, 'name' => 'female']];
if (Yii::$app->request->isPost) {
$count = count(Yii::$app->request->post('Todelete', []));
//start the loop from 1 rather than 0 and use the $count for limit
for ($i = 1; $i < $count; $i++) {
$model[] = new Todelete();
}
if (Model::loadMultiple($model, Yii::$app->request->post()) && Model::validateMultiple($model)) {
foreach ($model as $md) {
$md->save(false);
}
return $this->render('index');
}
}
return $this->render('create', [
'model' => $model,
'sex' => $sex
]);
}
我的观点
echo FormWizard::widget(
[
'formOptions' => [
'id' => 'my_form_tabular'
],
'steps' => [
[
//should be a single model or array of Activerecord model objects but for a single model only see wiki on github
'model' => $model,
//set step type to tabular
'type' => FormWizard::STEP_TYPE_TABULAR,
'fieldConfig' => [
'sex' => [
'widget' => Select2::class,
'containerOptions' => [
'class' => 'form-group'
],
'options' => [
'data' => $data,
'options' => [
'class' => 'form-control'
],
'theme' => Select2::THEME_BOOTSTRAP,
'pluginOptions' => [
'allowClear' => true,
'placeholder' => 'Select sex'
]
],
//set tabular events for select2 fix which doesnot work correctly after cloning
'tabularEvents' => [
'beforeClone' => "function(event, params){
//fix for select2 destroy the plugin
let element = $(this);
element.select2('destroy');
}",
"afterClone" => "function(event, params){
//bind select2 again after clone
let element = $(this);
let elementId = $(this).attr('id');
let dataKrajee = eval(element.data('krajee-select2'));
let dataSelect2Options = element.data('s2-options');
$.when(element.select2(dataKrajee)).done(initS2Loading(elementId, dataSelect2Options));
}",
"afterInsert" => "function(event,params){
//initialize the options for the select2 after initializing
//changed according to my environment
let selectElement = $(this).find('.field-todelete-'+params.rowIndex+'-sex > select');
let dataKrajee = eval(selectElement.data('krajee-select2'));
selectElement.select2(dataKrajee);
}"
]
]
]
]
]
]
);
https://cdn1.imggmi.com/uploads/2019/8/31/158dc0f338e0d780747c5f72fa2ed6bb-full.png https://cdn1.imggmi.com/uploads/2019/8/31/4e394e87aa162d3f457c32af8d30373b-full.png
原因
您指出的问题确实存在,您是对的。但这个问题与最近对 kartik\select2 @V2.1.4
的更改有关。演示链接使用的是 select2 V2.1.3
的旧版本,其中没有定义此 dataset
属性,因此可以正常工作。
小部件未集成所有这些更改,并留给了正在集成小部件的用户
The reason is that it won't be possible to control it correctly inside the plugin as there could be any widget a user wants to use and going to keep adding the code for every other widget isn't what I would vote for. So a better approach would be to provide the event triggers for the specific actions which require a pre or post-processing of an element, where according to the needs the user can adjust his code
疑难解答
关于这个问题,有一个新的数据集属性 data-select2-id
,它包含 select2 绑定到的输入的名称,并且克隆新元素后,该属性未更新为较新的元素 ID,这导致旧的 select 元素消失。
见下图,它来自我自己的代码,所以请忽略 address-0-city
字段名称,因为它与您的代码无关,仅供理解
解决方案
所以我们需要将afterInsert
事件中的代码改成下面的代码
let selectElement = $(this).find('.field-todelete-'+params.rowIndex+'-sex > select');
let dataKrajee = eval(selectElement.data('krajee-select2'));
//update the dataset attribute to the
if (typeof selectElement[0].dataset.select2Id !== 'undefined') {
//get the old dataset which has the old id of the input the select2 is bind to
let oldDataSelect2Id = selectElement[0].dataset.select2Id;
//delete the old dataset
delete selectElement[0].dataset.select2Id;
//add the new dataselect pointing to the new id of the cloned element
let newDataSelect2Id = oldDataSelect2Id.replace(
/\-([\d]+)\-/,
'-' + parseInt(params.rowIndex) + '-'
);
//add the new dataset with the new cloned input id
selectElement[0].dataset.select2Id= newDataSelect2Id;
}
selectElement.select2(dataKrajee);
我会在接下来的几天更新 wiki 文档上的代码和代码示例以及演示。
希望对您有所帮助。
这通常发生在使用小部件的 ID 发生冲突时。 通过检查 HTML 页面来确认这没有发生。 特别注意这些部分(此代码只是示例):
<Block1>
<select id = "todelete-0-sex">
</Block1>
<Block2>
<select id = "todelete-1-sex">
</Block2>
<Script>
// ...
$("# Todelete-0-sex").select2({...});
// ...
$("#Todelete-1-sex").select2({...});
// ...
</Script>
我已经在全新安装的 Yii2 (2.0.25) 上复制了您的代码,使用以下两个组件:
- buttflattery/yii2-formwizard (1.4.6)
- kartik-v/yii2-widget-select2 (v2.1.3)
进行一些与使代码正常工作无关的小改动,一切似乎都正常。
回顾
- 验证创建两者时没有冲突 小部件
- 检查 "yii2-formwizard" 和 "yii2-widget-select2" 组件的版本
MyController.php(控制器)
...
public function actionTest()
{
//$this->layout = 'layout2';
$model = [new Todelete(['id' => 1, 'name' => 'a', 'sex' => 'male']), new Todelete(['id' => 2, 'name' => 'b', 'sex' => 'male']), new Todelete(['id' => 3, 'name' => 'c', 'sex' => 'female'])];
$sex = [['id' => 1, 'name' => 'male'], ['id' => 2, 'name' => 'female']];
if (Yii::$app->request->isPost) {
$count = count(Yii::$app->request->post('Todelete', []));
//start the loop from 1 rather than 0 and use the $count for limit
for ($i = 1; $i < $count; $i++) {
$model[] = new Todelete();
}
if (Model::loadMultiple($model, Yii::$app->request->post()) && Model::validateMultiple($model)) {
foreach ($model as $md) {
$md->save(false);
}
return $this->render('index');
}
}
return $this->render('test', [
'model' => $model,
'sex' => $sex
]);
}
...
Todelete.php(型号)
...
use yii\base\Model; // NOTE: in your case your model will most likely extend ActiveRecord instead of Model class
class Todelete extends Model
{
public $id;
public $name;
public $sex;
/**
* @inheritdoc
*/
public function rules()
{
return [
['id', 'integer'],
[['sex', 'name'], 'string'],
];
}
}
...
create.php(查看)
use kartik\select2\Select2;
use \buttflattery\formwizard\FormWizard;
echo FormWizard::widget(
[
'formOptions' => [
'id' => 'my_form_tabular'
],
'steps' => [
[
//should be a single model or array of Activerecord model objects but for a single model only see wiki on github
'model' => $model,
//set step type to tabular
'type' => FormWizard::STEP_TYPE_TABULAR,
'fieldConfig' => [
'sex' => [
'widget' => Select2::class,
'containerOptions' => [
'class' => 'form-group'
],
'options' => [
//'data' => $data,
'options' => [
'class' => 'form-control'
],
'theme' => Select2::THEME_BOOTSTRAP,
'pluginOptions' => [
'allowClear' => true,
'placeholder' => 'Select sex'
]
],
//set tabular events for select2 fix which doesnot work correctly after cloning
]
]
]
]
]
);