简体   繁体   中英

Symfony2: Multiple collection type with dynamique add in the same form

i have a problem with collection type so what i want to do is: Product form that include two other form (atouts and proprietes) and i can add for one product multiple "atouts" and multiple "proprieties" so i use collection type and prototype with JavaScript in twig but the problem that always work with one form and not the both. help please think you. This is an image describe what i want to do 在此处输入图片说明

 <?php namespace IcebergBundle\\Form; use Symfony\\Component\\Form\\AbstractType; use Symfony\\Component\\Form\\FormBuilderInterface; use Symfony\\Component\\OptionsResolver\\OptionsResolver; use Symfony\\Component\\Form\\FormEvents; use Symfony\\Component\\Form\\FormEvent; use Symfony\\Component\\OptionsResolver\\OptionsResolverInterface; use IcebergBundle\\Form\\EventListener\\AddSsouscategorieFieldSubscriber; use IcebergBundle\\Form\\EventListener\\AddSouscategorieFieldSubscriber; use Symfony\\Component\\Form\\Extension\\Core\\Type\\CollectionType; use Symfony\\Component\\Form\\Extension\\Core\\Type\\CheckboxType; class ProduitType extends AbstractType { /** * @param FormBuilderInterface $builder * @param array $options */ public function buildForm(FormBuilderInterface $builder, array $options) { $builder ->add('nom','text' ,array('label' => 'Nom:', 'attr' => array('class' => 'form-control'))) ->add('Nouveau' ,CheckboxType::class, array('label' => 'Est ce que ce produit est nouveau ?','required' => false)) ->add('prix','text',array('label' => 'Prix:', 'attr' => array('class' => 'form-control'))) ->add('description','textarea' ,array('label' => 'Description:', 'attr' => array('class' => 'form-control'))) ->add('caracteristiques','ckeditor' ,array('label' => 'Caractéristiques techniques:', 'attr' => array('class' => 'form-control'))) ->add('souscategori', 'entity', array('label'=> ' Sous Categories','attr'=> array('class'=>'form-control'),'class' => 'IcebergBundle:Souscategorie' , 'required' => true , 'empty_value'=> 'Choisir sous categorie ')) ->add('sscategori', 'shtumi_dependent_filtered_entity' , array('label'=> ' Sous Sous Categories','attr'=> array('class'=>'form-control'), 'entity_alias' => 'region_by_country' , 'empty_value'=> 'Choisir sous sous categorie' , 'parent_field'=>'souscategori')) ->add('file','file',array('label' => 'Image: ', 'attr' => array('class' => 'btn btn-default') )) ->add('doc', CollectionType::class, array( 'label' => 'Document: ', 'attr' => array('class' => ' content-box-header panel-heading'), 'label_attr' => array('class' => 'h2'), 'entry_type' => DocumentType::class, 'allow_add' => true, 'allow_delete' => true, 'entry_options' => array( 'label' => false ) )) ->add('proprietes', CollectionType::class, array( 'label' => 'Les proprietes: ', 'label_attr' => array('class' => 'h2'), 'entry_type' => ProprieteType::class, 'allow_add' => true, 'allow_delete' => true, 'prototype' => true, 'by_reference' => false, 'prototype_name' => '__proprietes__', 'entry_options' => array( 'label' => false ) )) ->add('atouts', CollectionType::class, array( 'label' => 'Les atouts: ', 'label_attr' => array('class' => 'h2'), 'entry_type' => AtoutType::class, 'allow_add' => true, 'allow_delete' => true, 'prototype' => true, 'by_reference' => false, 'prototype_name' => '__atouts__', 'entry_options' => array( 'label' => false ) )) ->add('parent' ) ->getForm(); ; /* $propertyPathToSscategorie = 'sscategori'; $builder ->addEventSubscriber(new AddSouscategorieFieldSubscriber( $propertyPathToSscategorie)) ->addEventSubscriber(new AddSsouscategorieFieldSubscriber( $propertyPathToSscategorie)) ; */ } /** * @param OptionsResolver $resolver */ public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults(array( 'data_class' => 'IcebergBundle\\Entity\\Produit' )); } } 

And this my product/new.html.twig

 {% extends 'base_back.html.twig' %} {% block body %} {% for type, flashMessage in app.session.flashbag.all() %} <div class="alert alert-{{ flashMessage.type }} fade in"> <button class="close" data-dismiss="alert" type="button">×</button> {% if flashMessage.title is defined %} <strong>{{ flashMessage.title }}</strong> {{ flashMessage.message }} {% else %} {{ type }} {% endif %} </div> {% endfor %} <style > .btn-default1 { color: #333; background-color: #fff; border-color: #ccc; float: right; } .btn1 { display: inline-block; padding: 6px 12px; margin-bottom: 0; font-size: 14px; font-weight: normal; line-height: 1.428571429; text-align: center; white-space: nowrap; vertical-align: middle; cursor: pointer; background-image: none; border: 1px solid transparent; border-radius: 4px; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; -o-user-select: none; user-select: none; } </style> <h1>Ajouter un nouveau produit</h1> {{ form_start(form) }} </br> </br> <div class="row"> <div class="col-md-3"> {{ form_row(form.nom) }} </div> <div class="col-md-3"> {{ form_row(form.prix) }} </div> <div class="col-md-3"> {{ form_row(form.file) }} </div> </div> <br> {{ form_row(form.description) }} <br> {{ form_row(form.caracteristiques) }} <br> <div class="row"> <div class="col-md-4"> {{ form_row(form.souscategori) }} </div> <div class="col-md-4"> {{ form_row(form.sscategori) }} </div> </div> </br> </br> <!-- {{ form_label(form.doc, 'label', { 'attr': {'class': 'content-box-header panel-heading'} }) }}--> {{form_row(form.doc)}} <br> <h2> Atouts </h2> {{form_row(form.atouts)}} <br> <h2>Proprietes</h2> <ul class="proprietes" data-prototype="{{ form_widget(form.proprietes.vars.prototype)|e('html_attr') }}"> {% for propriete in form.proprietes %} <div class="del"> {{form_row(propriete)}}</div> {% endfor %} </ul> {{form_row(form.parent)}} <a class="btn btn-default" type="submit" href="{{ path('atout_new') }}">Suivant<i class="glyphicon glyphicon-eye-open"></i></a> <a class="btn btn-default" href="{{ path('produit_index') }}">Retourner à la liste<i class="glyphicon glyphicon-eye-open"></i></a> {{ form_end(form) }} <script> // setup an "add a tag" link var $addAtoutLink = $('<a href="#" >Ajouter un atout</a>'); var $newLinkLi = $('<div class="testdel"></div>').append($addAtoutLink); jQuery(document).ready(function() { p an "add a tag" link var $addpropLink = $('<a href="#" class="btn btn-primary">Ajouter une prop</a>'); var $newLinkLi = $('<div class="del"></div>').append($addpropLink); jQuery(document).ready(function() { // Get the ul that holds the collection of tags var $collectionHolder = $('ul.proprietes'); $collectionHolder.find('del').each(function() { addpropFormDeleteLink($(this)); }); // add the "add a tag" anchor and li to the tags ul $collectionHolder.append($newLinkLi); // count the current form inputs we have (eg 2), use that as the new // index when inserting a new item (eg 2) $collectionHolder.data('index', $collectionHolder.find(':input').length); $addpropLink.on('click', function(e) { // prevent the link from creating a "#" on the URL e.preventDefault(); // add a new tag form (see code block below) addpropForm($collectionHolder, $newLinkLi); }); }); function addpropForm($collectionHolder, $newLinkLi) { // Get the data-prototype explained earlier var prototype = $collectionHolder.data('prototype'); // get the new index var index = $collectionHolder.data('index'); var compteur = 1; // Replace '$$name$$' in the prototype's HTML to // instead be a number based on how many items we have var newForm = prototype.replace(/__proprietes__/g, index); // increase the index with one for the next item $collectionHolder.data('index', index + 1); // Display the form in the page in an li, before the "Add a tag" link li var $newFormLi = $('<div class="del"><h2>Prop</h2></div>').append(newForm); // also add a remove button, just for this example $newLinkLi.before($newFormLi); addpropFormDeleteLink($newFormLi); } function addpropFormDeleteLink($propFormLi) { var $removeFormA = $('<a href="#" class="btn1 btn-default1">supprimer cette prop</a>'); $propFormLi.append($removeFormA); $removeFormA.on('click', function(e) { // prevent the link from creating a "#" on the URL e.preventDefault(); // remove the li for the tag form $propFormLi.remove(); }); } </script> {% endblock %} <script src="https://code.jquery.com/jquery.js"></script> {% endblock %} 

If you need to dynamically add nested forms you definitely need a controller action to request the new form via ajax. If you have such an action please show it(and the script too).

Edit: Basically you need a script that will call your controller action via ajax when add button is clicked and retrieve the html for the new form and insert it in the dom.

For the controller you need to make an action that will initialize your form, render it into a variable and return the rendered html back to the script.

In case you don't want to go trough the hassle of making this yourself you can use the CollectionType provided by Symfony wich does exactly what you want: http://symfony.com/doc/current/reference/forms/types/collection.html

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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