Symfony表单-对CollectionType元素进行重新排序
Symfony form - reorder / sort CollectionType elements
我正在使用Symfony 2.7创建待办事项列表。Form
包含列表名称的简单文本字段和items
:的集合
class TodoType extends AbstractType {
public function getName() {
return 'todo_list';
}
public function setDefaultOptions(OptionsResolverInterface $resolver) {
$resolver->setDefaults(array(
'data_class' => 'AppBundle'Entity'TodoList',
));
}
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('name', 'text', array(
'label' => 'Name',
...
))
->add('create', 'submit', array(
'label' => 'Save',
...
));
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
$todoList = $event->getData();
$form = $event->getForm();
$form
->add('items', 'collection', array(
'type' => 'todo_list_item_type',
'allow_add' => true,
'allow_delete' => true,
//'by_reference' => false,
'data' => ($todoList != null ? $todoList->getItems() : null),
));
});
}
}
}
这很好用。项目数组包含在使用"数组样式"名称的表单中:
<form ...>
...
<ul class="sortable">
<li>
<input id="todo_list_items_0_name" class="item-name form-control" type="text" value="Shopping" placeholder="Name" required="required" name="todo_list[items][0][name]">
</li>
<li>
<input id="todo_list_items_1_name" class="item-name form-control" type="text" value="Wash car" placeholder="Name" required="required" name="todo_list[items][1][name]">
</li>
...
<ul>
现在我想使用jQuerySortable插件来重新排序项目。这很好用。用户可以根据自己的喜好对项目进行重新排序。然而,这对物品的存储顺序没有任何影响。
我认为问题很明显:可排序插件只更改DOM
中项目的位置,而项目名称(包括其数组索引)保持不变。因此,当表单提交时,Item0仍然具有index = 0
,无论它在列表中的新位置如何。
是否有任何内置解决方案来解决此问题我在那里找到的唯一解决方案是监听可排序插件的stop
事件(在重新排序完成后触发),并使用一些JavaScript手动查找/替换字段名称中的索引号。这当然有效,但很容易受到字段名称更改的影响。例如,如果将来的Symfony版本将使用some_field_name_0
而不是some_field_0_name
,则替换代码将不再工作。
另一个解决方案是,用一个额外的字段sortOrder
扩展Item
类,并将这些信息作为隐藏字段包含在表单中。我仍然需要使用JS手动更新这个索引,但至少我可以对格式有更多的控制权。
然而,我想知道是否还有更简单的方法。对集合类型进行排序并没有什么特别之处。所以,也许有一个开箱即用的解决方案
您的方法在我看来是合理的(不过我将进一步讨论另一种选择)。没有现成的解决方案,收集表单类型依赖于数据的"自然"顺序。
最后一个问题的解决方案是使用"原型"选项。在Twig视图中,您可以显示原型,即集合中任何(新)表单的HTML
如果您使用form_widget
或form_row
,这将自动完成,否则您可以执行此操作(从此处的文档中):
<ul class="tags" data-prototype="{{ form_widget(form.tags.vars.prototype)|e('html_attr') }}">
...
</ul>
然后您可以轻松可靠地获得表单名称:
// Get the data-prototype explained earlier
var prototype = $('.tags').data('prototype');
// I assume we use jQuery
var $prototype = $(prototype);
// Get the item name
// by convention, instad of a numeric index it will contain __name__
var itemName = $prototype.attr('name');
// We can replace '__name__' it to whatever you like
var nameFor1 = itemName.replace(/__name__/g, 1);
另一种方法
另一种方法是将position
字段添加到todo_list_item
元素。假设它是一个条令实体,你可以在上面使用Sortable条令扩展:你可以在文档中找到所有细节,尽管你不需要自己手动启用条令扩展,但你可以使用StofDoctrineExtensionBundle。
如果它是一个简单的数据数组(或者您不想添加扩展名,也不想将位置保存到数据库中),您可以从setItems
方法中重新排序项目。
- 使用JS或新查询对列表进行排序
- 主干中的比较器在添加新模型时需要排序调用
- 插入按字母顺序、javascript或jquery排序的新列表
- 无法从jQuery可排序列表中删除新添加的项
- 使用“可排序”时获取新元素信息
- JavaScript 将文本框存储中的值引入数组中,创建新数组进行排序
- 在使用可排序排序期间/之后显示使用 JSON 创建的列表中的项目位置
- React Native ListView 不会在排序或检索新数据后更新
- 使用 UI 可排序,在单击按钮时根据给定值将项目移动到新位置
- AngularJS:插入新项目后对列表重新排序
- jQuery dataTable 不会对新数据进行排序
- jQuery UI 可排序在克隆和附加新的可排序列表后不会刷新
- 如何使用布局管理器重新排序/排序嵌套视图而不重新渲染
- ractive js :与模板中键部分关联的嵌套对象列表的直接 DOM 插入排序/排序 #each 顺序
- 在backbone.js中,如何使用新的模型数据更新视图,同时在没有完整渲染的情况下保持排序顺序
- jQuery UI可排序-排序时表格单元格丢失边框
- 对对象数组进行排序,并将具有相同键/值对的对象推送到新数组
- 嵌套可排序新添加的项目不会移动
- 如何使用jquery同位素按日期(新)排序
- 对象数组的复合排序(排序)