4

Right now i have a FormType that contains the following:

$builder->add('name','text')
    ->add('save','submit',array('label'=>'Save', 'attr'=>array('class'=>'btn btn-primary')))
    ->add('reset','reset',array('label'=>'Reset Form', 'attr'=>array('class'=>'btn btn-warning')));

Right now i have a little bit of form themeing going on that renders the above as:

<form method="post" action="">
    <input type="hidden" name="_csrf_token" value="*********" />
    <div class="form-group">
        <label class="col-4">Name</label>
        <input type="text" name="form[name]" value="" placeholder="Name" />
    </div>
    <div class="form-group">
        <input type="submit" name="form[save]" value="Save" class="btn btn-primary" />
    </div>
    <div class="form-group">
        <input type="reset" name="form[reset]" value="Reset" class="btn btn-warning" />
    </div>
</form>

However what I would like the output to be is:

<form method="post" action="">
    <input type="hidden" name="_csrf_token" value="*********" />
    <div class="form-group">
        <label class="col-4">Name</label>
        <input type="text" name="form[name]" value="" placeholder="Name" />
    </div>
    <div class="form-group">
        <input type="submit" name="form[save]" value="Save" class="btn btn-primary" />
        <input type="reset" name="form[reset]" value="Reset" class="btn btn-warning" />
    </div>
</form>

Notice the buttons are in the same form group wrapper div. I want to know if there is a way to do this using only the FormType or editing the Form Theme. I dont want to change the views from using:

{{ form(form,{'method':'POST','attr':{'class':'form-horizontal'} }) }}

I am aware this can be accomplished if I render the buttons from the form in a custom manner.

Chase
  • 9,289
  • 5
  • 51
  • 77

2 Answers2

6

Update

A bundle that solves this for you that basically does what i suggest but nicer: http://bootstrap.braincrafted.com/components.html#forms


This is far from the most elegant way to do this but i havent found any other means to do this.

I have a working solution that involves modifying the FormType a bit and also overriding some blocks in form_div_layout.html.twig

{# form_div_layout.html.twig #}

{% block button_row %}
{% spaceless %}
    {% if 'data-first-button' in attr %}
    <div class="form-group">
        <div class="col-12">
    {% endif %}
    {{ form_widget(form) }}
    {% if 'data-last-button' in attr %}
        </div>
    </div>
    {% endif %}
{% endspaceless %}
{% endblock button_row %}

{% block button_attributes %}
{% spaceless %}
    id="{{ id }}" name="{{ full_name }}"{% if disabled %} disabled="disabled"{% endif %}
    {% for attrname, attrvalue in attr %}{% if attrvalue != 'data-first-button' and attrvalue != 'data-last-button'%}{{ attrname }}="{{ attrvalue }}"{%endif%}{% endfor %}
{% endspaceless %}
{% endblock button_attributes %}

What this does is it looks for the data-first-button and data-last-button attributes on buttons and adds the containing divs for the respective ones. Then in the button attributes block we look for those attributes and ignore them. Then in the form type we just have to add the attr to the right buttons like this:

$builder->add('name','text')
   ->add('save','submit',array('label'=>'Save', 'attr'=>array('class'=>'btn btn-primary','data-first-button')))
   ->add('reset','reset',array('label'=>'Reset Form', 'attr'=>array('class'=>'btn btn-warning','data-last-button')));
Chase
  • 9,289
  • 5
  • 51
  • 77
-2

I have a better answer (a more modern solution than the last accepted answer from 2 yrs ago.

Comment out in your controller where your adding those elements

 /* -   
   ->add('cancel', 'button', array())
   ->add('save', 'submit', array())
*/

Now set up your form like this

{{ form_start(form,  {'attr': {'id': 'your-form-id'},}) }}
{{ form_errors(form) }}
{{ form_row(form.name) }}

<div class="form-group">
    <button id="form_reset"name="form[reset]" type="button">Reset</button>
    <button id="form_save" name="form[save]" type="submit">Save Form</button>
</div>

{{ form_end(form) }}

You always have the option of a jQuery solution, but the above is the correct way to customize your form

or a jQuery solution might look something like this;

var formInputSave = $('input:form[save]'),
    formInputReset = $('input:form[reset]'),
    formGroupReset = formInputReset.parent();   

    //save the form group with the form[save] in it.  
    //Append the reset input to it, then remove the initial form group
    $(formInputSave).append(formInputReset);
    $(formGroupReset).empty(); 
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
blamb
  • 4,220
  • 4
  • 32
  • 50
  • 1
    This requires that you manually setup those forms in all of your views. If this was a 1 off form that needed it, your solution may work. However where a more global solution is needed this is only more cumbersome and in no way OOP or more modern. – Chase May 04 '15 at 18:34
  • 1
    hmm your opting for a "global solution" to solve a styling issue? come on, my solution is way better(NOT the jquery option, note i dont even like that option). you just move around your form code a bit on teh fricker that you want the buttons tweaked on... ill stick with my solution, the heck if i want add a bundle to adjust a button on a form thats created by another bundle. to make matters worse, i cant see how my solution is a downvoted one either. oh well, to each his own – blamb May 05 '15 at 21:37