【问题标题】:Symfony 2 form prototypes within prototypes - double $$name fieldSymfony 2 在原型中形成原型 - 双 $$name 字段
【发布时间】:2012-03-14 18:23:57
【问题描述】:

我需要一些关于原型中的原型的帮助。 Symfony 在生成表单原型方面非常聪明,但是一旦您向下一层(即原型中的原型),它就会为两个原型重用 $$name$$。

这就是我的实体的原型字段的样子。 JQuery 用正确的索引值换出 $$name$$(基于子节点的数量)

 <input type="text" id="entry_entities_$$name$$_contactFax" name="entry[entities][$$name$$][contactFax]" value="" />

到目前为止一切顺利。但是当你更深一层时,Symfony 也使用 $$name$$ 来下一层——这里是实体属性的原型:

<div id="entry_entities_123_properties" data-prototype="    
    &lt;label for=&quot;entry_entities_$$name$$_properties_$$name$$_name&quot;&gt;Name&lt;/label&gt;
    &lt;input type=&quot;text&quot; id=&quot;entry_entities_$$name$$_properties_$$name$$_name&quot; name=&quot;entry[entities][$$name$$][properties][$$name$$][name]&quot; value=&quot;&quot; /&gt;

这意味着(在此示例中,实体 ID 为 123)所有属性的 ID 为 123:

name="entry[entities][123][properties][123][name]"
name="entry[entities][123][properties][123][name]"
name="entry[entities][123][properties][123][name]"

等等

在我看来,解决这个问题的最好方法是使用 $$somethingelse$$ 作为属性——有谁知道这是在哪里设置的——或者有没有人有一个完整的 JS 示例来解决这个问题?我开始对每一行的第二个 $$name$$ 进行可怕的查找/替换,但它变得非常混乱。我确信有一种简单的方法可以做到这一点,但我在互联网上找不到任何指南。

【问题讨论】:

  • 你在prototype()函数中传递了'$$name$$',你不能在那里改吗?
  • 实际上,我在发布后查看了 Symfony 代码。 $$name$$ 被硬编码到 CollectionType 中。看看 Symfony\Component\Form\Extension\Core\Type\CollectionType.php
  • @meze 谢谢你。我不确定你是否让我的日子过得更好 :-) 我是做一些 JS 黑客还是在 sf 2.1 beta 上运行我的项目?
  • 取决于您有多少时间;) 2.1 测试版尚未公布。您还可以使用 'prototype_name' 选项定义自己的集合类型(请参阅下面的答案)。

标签: php jquery forms symfony symfony-2.0


【解决方案1】:

此代码适用于 symfony 2.0(在 2.1+ 中,您只需将名称传递给 prototype() 函数):

您可以使用所需的选项创建自己的集合类型:

<?php

namespace YourBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\Extension\Core\EventListener\ResizeFormListener;
use Symfony\Component\Form\Extension\Core\Type\CollectionType as BaseCollectionType;

class CollectionType extends BaseCollectionType
{
    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilder $builder, array $options)
    {
        if ($options['allow_add'] && $options['prototype']) {
            $prototype = $builder->create($options['prototype_name'], $options['type'], $options['options']);
            $builder->setAttribute('prototype', $prototype->getForm());
        }

        $listener = new ResizeFormListener(
            $builder->getFormFactory(),
            $options['type'],
            $options['options'],
            $options['allow_add'],
            $options['allow_delete']
        );

        $builder
            ->addEventSubscriber($listener)
            ->setAttribute('allow_add', $options['allow_add'])
            ->setAttribute('allow_delete', $options['allow_delete'])
        ;
    }

    /**
     * {@inheritdoc}
     */
    public function getDefaultOptions(array $options)
    {
        $defaultOptions = parent::getDefaultOptions($options);
        $defaultOptions['prototype_name'] =  '$$name$$';
        return $defaultOptions;
    }
}

然后只需定义一个服务:

tags:
    - { name: form.type, alias: collection }

并将其用作 Symfony 的集合,但带有原型名称参数。

【讨论】:

  • 我在尝试重写和区分占位符 3 天后看到了这个答案。我希望我早点看到它。 +10000000 !
  • @renoirb 好!但请记住,这是 2.0 的 hack。从 v2.1 开始,您可以将名称传递给 prototype() 函数。
【解决方案2】:

我不熟悉 Symfony,但在 Javascript 中使用 String.replace() 默认只替换第一个匹配项,因此您可以非常安全地使用它。

$('mydiv').html
(
    $('mydiv').html().replace('$$name$$', 123).replace('$$name$$', 456);
);

如果内容被拆分到不同的行,并且您想在这些行中进行替换,您可以使用 .split() 将其拆分为一个数组,for() 覆盖它,然后将 .join() 重新组合在一起。

【讨论】:

  • 感谢您的回答 - 我相信您的想法会奏效,但结果将是大量的 Javascript。 Meze 的回答符合 Symfony2 的最佳实践。
  • 公平 :) 主要作为一个选项发布,期待有人提出与 Symfony 相关的解决方案。很高兴你有一种让你满意的方式
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-26
  • 2019-03-05
  • 2011-06-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多