我正在使用Symfony 2.7来创建ToDo列表。 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),
));
});
}
}
}
这很好用。 items数组包含在表单中,使用"数组样式"名:
<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>
现在我想使用jQuery Sortable Plugin重新排序项目。这很好用。用户可以根据自己的喜好对商品进行重新排序。但是,这对项目的存储顺序没有任何影响。
我认为问题很明显:可排序插件只会更改DOM
中项目的位置,而项目名称(包括其数组索引)保持不变。因此,无论表单中的新位置如何,Item0在表单提交时仍然有index = 0
。
解决方案是否有任何解决方案?我发现唯一的解决方案是收听可排序插件的stop
事件(触发一次重新排序完成后)使用一些JavaScript手动查找/替换字段名称中的索引号。这当然会起作用,但很容易改变字段名称。例如,如果未来的Symfony版本将使用some_field_name_0
而不是some_field_0_name
,则替换代码将不再起作用。
另一种解决方案是,使用附加字段Item
扩展sortOrder
类,并将此信息作为隐藏字段包含在表单中。我仍然需要使用JS手动更新这个索引,但至少我可以更好地控制格式。
但是我想知道是否有更简单的方法。排序集合类型并不特别。那么也许有开箱即用的解决方案?
答案 0 :(得分:1)
你的方法对我来说是合理的(虽然我会进一步讨论另一种选择)。没有开箱即用的解决方案,收集表单类型依赖于数据&#34;自然&#34;顺序。
你最后一个问题的解决方案是使用&#34;原型&#34;选项。在Twig视图中,您可以显示原型,即集合中任何(新)表单的HTML
如果您使用form_widget
或form_row
,则会自动完成此操作,否则您可以执行此操作(来自文档here):
<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
字段。假设它是一个Doctrine实体,你可以在其上使用Sortable Doctrine扩展:你会在文档中找到所有细节here,虽然你不需要自己手动启用Doctrine扩展,你可以使用StofDoctrineExtensionBundle。
如果它是一个简单的数据数组(或者您不想添加扩展名,或将位置保存到数据库中),您可以在setItems
方法中重新排序项目。