symfony - Symfony 3 带有子集合的表单集合
问题描述
我有一个名为“planes”的字段的表单。
该字段可以是多个(集合),具有以下子字段: - 速度 - 重量 - 颜色 - 引擎
子字段“engines”也是字段的集合: - rpm -fuel_type - weight
我想知道 Symfony 表单构建器会是什么样子,因为用户应该可以根据需要添加任意数量的平面。这同样适用于发动机。
解决方案
它看起来像这样:
具有平面集合的类中的生成器:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('planes', CollectionType::class, array(
'entry_type' => PlaneType::class,
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,// this will call get/set of your entity
'prototype' => true, // is needed coz there will be 2 prototypes
'prototype_name'=> '__planes__'//1-st prototype name
'attr' => [
'class' => 'embeddedCollection'
]
));
}
PlaneType 类中的生成器:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('speed');
$builder->add('weight');
$builder->add('color');
$builder->add('engines', CollectionType::class, array(
'entry_type' => EngineType::class,
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,// this will call get/set of your entity
'prototype' => true, // is needed coz there will be 2 prototypes
'prototype_name'=> '__engines__',//2 -nd prototype
'attr' => [
'class' => 'subEmbeddedCollection'
]
));
}
EngineType 类中的生成器:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('rpm');
$builder->add('fuel_type');
$builder->add('weight');
}
此外,您应该为动态添加/删除字段添加一些 javascript,在添加过程中您应该使用字段编号的 id 交换原型名称。
编辑: 一些带有 JQuery 的 js 代码使其在前端工作:
function initCollection(collectionHolder, addItemButton, deleteItemButton, prototypePattern) {
let $addItemButton = $(addItemButton);
// Get the ul that holds the collection of tags
let $collectionHolder = $(collectionHolder);
// add a delete link to all of the existing tag form li elements
$collectionHolder.children('.form-group').each(function () {
addFormDeleteLink($(this), deleteItemButton);
});
// add the "add a tag" anchor and li to the tags ul
$collectionHolder.append($addItemButton);
// count the current form inputs we have (e.g. 2), use that as the new
// index when inserting a new item (e.g. 2)
$collectionHolder.data('index', $collectionHolder.find(':input').length);
//when new element is added then trigger event on collection
let addNewElementEvent = jQuery.Event ('element-added');
let addNewChildCollection = jQuery.Event ('new-child-collection');
$addItemButton.on('click', function (e) {
// add a new tag form (see next code block)
lastAddedElement = addForm($collectionHolder, $addItemButton, deleteItemButton, prototypePattern);
if($collectionHolder.hasClass('embeddedCollection')) {
$collectionHolder.trigger(addNewElementEvent);
}else{
$collectionHolder.trigger(addNewChildCollection);
}
});
}
function addForm($collectionHolder, $addItemButton, deleteItemButton, prototypePattern) {
// Get the data-prototype explained earlier
let prototype = $collectionHolder.data('prototype');
// get the new index
let index = $collectionHolder.data('index');
let newForm = prototype;
newForm = newForm.replace(prototypePattern, index);
// increase the index with one for the next item
$collectionHolder.data('index', index + 1);
// Display the form in the page in an li, before the "Add a tag" link li
let $newFormLi = $(newForm);
$addItemButton.before($newFormLi);
addFormDeleteLink($newFormLi, deleteItemButton);
return $newFormLi;
}
function addFormDeleteLink($tagFormLi, deleteItemButton) {
let $removeFormButton = $(deleteItemButton);
$tagFormLi.append($removeFormButton);
$removeFormButton.on('click', function (e) {
// remove the li for the tag form
let $parent = $tagFormLi.parent();
$tagFormLi.remove();
if($removeFormButton.hasClass('labels-rewrite'))
{
$parent.trigger(jQuery.Event('labels-rewrite'));
}
});
}
父集合应该有 class embeddedCollection
,如果添加了新的子集合,则该事件'element-added'
将被触发。如果添加了带有子引擎集合的新平面,您需要在添加的引擎集合上调用 initCollection 方法。
所以首先你需要初始化现有的集合,例如:
//init all sub collections of engines of the planes
$('.subEmbeddedCollection').each(function () {
initCollection($(this),
'<button type="button">Add engine</button>',
'<button type="button" >Delete engine</button>',
/__engines__/g
);
});
//init main collection of planes
let $collectionHolder = $('.embeddedCollection');
initCollection($collectionHolder,
'<button type="button">Add plane</button>',
'<button type="button" >Delete plane</button>',
/__planes__/g
);
然后,当在主平面集合中触发事件元素添加时,您应该初始化所有动态添加的引擎子集合:
//init collection in added plane
$collectionHolder.on('element-added', function () {
let $lastChildCollection = $(this).find('.engines').last();
initCollection($lastChildCollection,
'<button type="button">Add engine</button>',
'<button type="button" >Delete engine</button>',
/__exam_type_lab_request__/g
);
});
推荐阅读
- reactjs - TypeError: (0 , _reactNative.unstable_createElement) 不是函数
- docker - 我可以在 GitHub Actions 工作流程中引用 Dockerfile 而不是图像吗?
- java - 如何对具有使用数据库连接的方法的类进行单元测试?
- windows - shell:startup打开的echo目录
- tensorflow - 关于量化 Mobilenet-SSD V2 所需的 300x300 输入的一些问题
- reactjs - 我无法通过单击按钮安装 PWA
- reactjs - 喊/发送 Blob 对象在 webRTC 中不起作用
- java - 使用 PowerMockito 进行 JUnit 参数化和非参数化测试
- mql4 - 为什么我在下面的代码中出现参数转换不允许错误?
- swift - 如何快速复制 Snapchat Map?