简体   繁体   English

基于表单选择的Symfony动态表单

[英]Symfony dynamic form based on form selection

Lets say we have form where we have to choose membership type for a customer. 可以说我们有一个表格,其中我们必须为客户选择会员类型。 Each type of membership has different number of co members (entity type of select fields) what can be chosen for that membership. 每种类型的成员资格都有不同数量的共同成员(选择字段的实体类型),可以为该成员资格选择什么。

Now i need to implement form where based on membership type selection number of entity type of select fields will be added to form. 现在,我需要实现一个表单,其中将基于成员资格类型选择将选择字段的实体类型的数量添加到表单中。

Membership type selection will be bade when form is already rendered to fronted. 当表单已经呈现在前面时,成员资格类型选择将变得很困难。

Question is maybe too general, but how exactly i should implement this FormType ? 问题也许太笼统了,但是我应该如何实现这个FormType呢?

I have looked this coockbook entry: http://symfony.com/doc/current/cookbook/form/dynamic_form_modification.html#cookbook-form-events-submitted-data But as i understand this EventListener works during regular form rendering, so before it is displayed to frontend. 我看过这个coockbook条目: http ://symfony.com/doc/current/cookbook/form/dynamic_form_modification.html#cookbook-form-events-submitted-data但据我了解,此EventListener在常规表单呈现期间有效,因此在它显示在前端。 Should i implement AJAX hocus pocus to form MembershipType field, so when it's chosen, whole form is rendered again ? 我是否应该实现AJAX hocus pocus以形成MembershipType字段,以便在选择它时再次呈现整个表单?

What must be general logic of this kind of task ? 这种任务的一般逻辑是什么?

As @keyboardSmasher mentioned in his comment a multi-step form strategy could be a good solution for you. 正如@keyboardSmasher在他的评论中提到的那样,多步表单策略可能是您的理想解决方案。 There are plenty of ways to make this possible but lets explore a bit. 有很多方法可以实现这一点,但让我们继续探索。

First of all, form events are not only useful prior to rendering. 首先,表单事件不仅在渲染之前有用。 You can intercept the form rendering process at numerous points. 您可以在很多地方截取表单呈现过程。 You could detect that the record is a new record and only display ( or not display ) particular fields if that is the case. 您可以检测到该记录是新记录,并且在这种情况下,仅显示(或不显示)特定字段。 You could alter the newly submitted form data prior to persisting it. 您可以在持久保存之前更改新提交的表单数据。 You can show fields only to those with the right permissions ( use a form factory as a service injecting the security context for this one ) or even show a list of friends for a user to connect with based on some criteria such as shown in the cookbook. 您可以仅向具有适当权限的用户显示字段(使用表单工厂作为服务,为其注入安全上下文),甚至可以根据某些条件(例如,菜谱中的内容)显示供用户连接的朋友列表。 。 Form events are very powerful. 表单事件非常强大。 Further, you could also create a custom validator which checks that the chosen options are allowed for, in your case, the membership that is chosen and I highly recommend doing so ( this is very much separate from the form and should be more closely tied to your models/documents/entities/etc. ) 此外,您还可以创建一个自定义验证器 ,以检查是否允许选择的选项(在您的情况下),对于您所选择的成员资格,我极力建议这样做(这与表格非常分开,应与之紧密联系您的模型/文档/实体/等。)

If I understand correctly, you want to show a multiple select field containing options specific to a particular type of membership. 如果我理解正确,则希望显示一个包含特定于特定成员类型选项的多重选择字段。 That select field, let's call it MembershipSubOptions, is populated with options after the user selects a membership type. 用户选择成员资格类型后,该选择字段(称为“ MembershipSubOptions”)将填充选项。 I hope that's correct. 我希望这是正确的。 Be warned, the following is off the top of my head aside from a few links I googled quickly and it's very late here but it should be somewhat close to what your trying to achieve. 请注意,除了我快速搜索过的几个链接之外,以下内容不在我的脑海中,这已经很晚了,但它应该与您要实现的目标有些接近。

You can do this starting with basic ajax ( i would not recommend hocus pocus though, that stuff gets really weird ;-) ). 您可以从基本的ajax开始进行操作(尽管我不推荐hocus pocus,但这些东西确实很奇怪;-))。 On the client side you can use a library such as Select2 to ease population of the MembershipSubOptions via ajax. 在客户端,您可以使用Select2之类的库通过ajax减轻MembershipSubOptions的填充。 Setup a route to return options ( json ) based on the membership chosen to populate your select. 设置一条基于选择的成员资格来返回选项(json)的路由,以填充您的选择。 Now you have a select populated with the options relevant to that membership type and, if I understand correctly, those options came from a data store so from the forms perspective it's an entity type. 现在,您有一个与该成员资格类型相关的选项填充的选择,如果我理解正确,这些选项来自数据存储,因此从表单角度来看,它是一种实体类型。

I'm guessing you want the user to select multiple options from this select field and those options are likely stored as a ManyToMany relation for that user. 我猜您希望用户从此选择字段中选择多个选项,而这些选项很可能存储为该用户的ManyToMany关系。 Since we are dealing with an entity type here, we need to transform the data that is submitted so the form component knows how to deal with it. 由于我们在这里处理实体类型,因此我们需要转换提交的数据,以便表单组件知道如何处理它。 Let's create a rather empty MembershipSubOptionsType form type. 让我们创建一个相当空的MembershipSubOptionsType表单类型。 It will look something like the following: 它将类似于以下内容:

use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;

class MembershipSubOptionsType extends AbstractType
{
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(

            )
        );
    }

    public function getParent()
    {
        return 'hidden';
    }

    public function getName()
    {
        return 'membership_suboptions';
    }
}

In the main form add something like the following for your sub options select field. 在主表单中,为您的子选项选择字段添加类似以下内容的内容。 You'll notice that I reference $this-em and pass it to the transformer. 您会注意到我引用了$ this-em并将其传递给转换器。 Setup your form to be managed by a factory class registered as a service and inject the Doctrine Manager so you can get the entity records you need. 将表单设置为由注册为服务的工厂类来管理,并注入“教义管理器”,以便获得所需的实体记录。

$membershipSubOptionsTransformer = new MembershipSubOptionsTransformer($this->em);
$builder->add($builder->create('membershipSubOptions', new \My\GreatBundle\Form\Type\MembershipSubOptionsType(), array(
                'required'      => true, // or false if they arent required
                'label'         => 'membership.suboptions.label',
                'attr'          => array(
                    'class'     => 'membershipSubOptionsSelect',
                    'data-placeholder' => 'Select some options'
                )
            ))->addModelTransformer($membershipSubOptionsTransformer))

Now your ready to actually handle the membershipSubOptions in some way. 现在,您已经准备好以某种方式实际处理MembershipSubOptions了。 In the select on the client side each of them is nothing more than a string or an integer but in your application they represent a real record/model/entity. 在客户端的select中,它们每个都不过是字符串或整数,而在您的应用程序中,它们表示真实的记录/模型/实体。 The form knows to pass the submitted data to a transformer now which you will still need to build. 表单知道现在将提交的数据传递给转换器,您仍然需要构建它。 To finish this up and not end up writing a novel, checkout the Data Transformer documentation . 要完成此操作而不要最终写小说,请查阅Data Transformer文档 It's much more clear about the actual transformers than I could ever be. 实际的变压器比我想象的要清楚得多。

Now you can dynamically populate some select field with relevant options that aren't initially provided when the form was rendered. 现在,您可以使用呈现表单时最初未提供的相关选项来动态填充某些选择字段。 Interestingly, the data transformer goes both ways so when your form is edited, the currently set options will be set and when they are initially submitted or updated they will be "transformed" into something your application understands. 有趣的是,数据转换器会双向运行,因此在编辑表单时,将设置当前设置的选项,并且在最初提交或更新它们时,会将它们“转换”为应用程序可以理解的内容。

I would set the options select field to hidden for a new record without a membership and set it to visible with js once a membership is selected. 我会将选项选择字段设置为隐藏,以获取没有成员资格的新记录,并在选择成员资格后将其设置为与js可见。 For editing forms, you'll want to use a form event ( or similar method ) to set the visibility to visible. 对于编辑表单,您需要使用表单事件(或类似方法)将可见性设置为可见。

I hope all that makes some sense. 我希望所有这些都有意义。 Like I said, top of the head so YMMV but I hope that this puts you on the right path. 就像我说的那样,YMMV非常重要,但我希望这会让您走上正确的道路。 I'm sure there are many other ways to accomplish what you want to do so I'm looking forward to reading others thoughts as well. 我确信还有许多其他方法可以完成您想做的事情,因此我也希望能阅读其他人的想法。 Please let us all know what your final solution looks like so we all become better informed. 请让我们所有人都知道您最终的解决方案是什么样的,以便我们都更加了解情况。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM