【问题标题】:Symfony form - reorder / sort CollectionType elementsSymfony 表单 - 重新排序/排序 CollectionType 元素
【发布时间】:2016-07-22 06:46:13
【问题描述】:

我正在使用 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,则替换代码将不再起作用。

另一种解决方案是使用附加字段 sortOrder 扩展 Item 类,并将此信息作为隐藏字段包含在表单中。我仍然需要使用 JS 手动更新这个索引,但至少我可以更好地控制格式。

但是我想知道是否没有更简单的方法。对集合类型进行排序并没有什么特别之处。那么也许有一个开箱即用的解决方案?

【问题讨论】:

    标签: javascript jquery forms symfony jquery-ui-sortable


    【解决方案1】:

    您的方法在我看来是合理的(尽管我将进一步讨论另一种选择)。没有开箱即用的解决方案,集合表单类型依赖于数据“自然”顺序。

    最后一个问题的解决方案是使用“原型”选项。在 Twig 视图中,您可以显示原型,即集合中任何(新)表单的 HTML。
    如果您使用form_widgetform_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 方法中重新排序项目。

    【讨论】:

    • 谢谢!将__name__ 替换为一些在重新设置索引号时可以轻松识别的自定义内容是一个不错的选择。我已经使用原型将新项目动态添加到表单中,我可以在此步骤中轻松更改 __name__ 值。但是,我不明白这对于已经存在并因此与表单一起加载的项目是如何工作的。我对这些价值观/项目没有任何影响。
    • 采用您找到的解决方案,重新命名字段,以便将正确的顺序“发送”到 Symfony,它为您提供了一个生成新名称的模板。从而使您的解决方案不受您提到的 Symfony 升级/更改的影响。
    猜你喜欢
    • 1970-01-01
    • 2019-02-27
    • 2011-03-04
    • 1970-01-01
    • 2018-05-08
    • 1970-01-01
    • 1970-01-01
    • 2014-05-22
    • 1970-01-01
    相关资源
    最近更新 更多