How could i change the label of a form field after a submit of them?
Example form
class TestType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('test', 'number')
->add($options['data']->getId() > 0 ? 'save' : 'add', 'submit')
;
}
public function finishView(FormView $view, FormInterface $form, array $options)
{
if($form->has('add'))
{
$form->remove('add');
$form->add('add', 'submit', array('label' => 'save'));
}
}
public function getName()
{
return '';
}
}
The form is completely generated with "{{ form(form) }}".
I only use the FormType.
There is a add button if the data['id'] is lower as 1. if the id is higher as 0 there is a save button.
After the first submit of a new form, the entity is saved and after finished page load i see the "add" field instead the "save" field.
If i reload the complete page manually, i see the save button...
You don't need the finishView method to achieve what you want. You're removing and re-adding the add button in there. This does not make any sense.
public function buildForm(FormBuilderInterface $builder, array $options)
{
$buttonName = $options['data']->getId() > 0 ? 'save' : 'add';
$builder
->add( /* ... */)
->add($buttonName, 'submit', array('label' => $buttonName))
;
}
Related
I want to create form with composition pattern like this:
https://symfony.com/doc/current/form/inherit_data_option.html
I use Symfony 3.
and it's working. I have each element like single object and add this.
but finally my form elements names have name like
form[subform][element]
How to make flat structure without subform in name attribute?
use AppBundle\Base\Form\NickType;
use AppBundle\Base\Form\MailType;
use AppBundle\Base\Form\PassType;
use AppBundle\Base\Form\UserType;
class RegisterType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('nick', NickType::class)
->add('mail', MailType::class)
->add('password', PassType::class)
->add('repeat_password', PassType::class)
(etc...)
and SINGLE ELEMENT
class NickType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('nick', TextType::class);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'inherit_data' => true
));
}
}
You don't need to define a NickType if it only inherits a TextType. You can remove NickType, MailType, etc.
You can just do:
class RegisterType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('nick', TextType::class)
;
(etc...)
If you want to reuse a form field, you have to create a Custom Form Field Type:
class NickType extends AbstractType
{
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
//...
));
}
public function getParent()
{
return TextType::class;
}
}
You can remove form[] from the element name, but removing this is not really recommended, because when you read the request to populate form data you can identify the form by its form name. (via)
You can set the name of the root form to empty, then your field name
will be just form. Do so via
// the first argument to createNamedBuilder() is the name
$form = $this->get('form.factory')->createNamedBuilder(null, 'form', $defaultData)
->add('from', 'date', array(
'required' => false,
'widget' => 'single_text',
'format' => 'dd.MM.yyyy'
));
(via)
In symfony 2.5.6,
how to change options dynamically in symfony2 form, by example:
// src/AppBundle/Form/Type/TaskType.php
namespace AppBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
class TaskType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('task')
->add('dueDate', null, array('widget' => 'single_text'))
->add('save', 'submit');
if (condition) {
//how to change option of 'task' or 'dueDate' by example
//something like this, but addOption doesn't exist and i don't find any usefull method
$builder->get('dueDate')->addOption('read_only', true)
}
}
public function getName()
{
return 'task';
}
}
Need to use event ?
http://symfony.com/doc/current/cookbook/form/dynamic_form_modification.html
Or this
foreach($builder->all() as $key => $field) {
if ($key == 'dueDate')) {
$options = $field->getOptions();
$options = array_merge_recursive($options, array('read_only' => true));
$builder->remove($key);
$builder->add($key, $field->getName(), $options);
}
}
#with 'Could not load type "dueDate"' error when i display my form in a browser!
How to to do? Best practice?
Thanks!
I dont't know what do you mean by 'best practice', but why not to do it like this:
$builder
->add('dueDate', null, array('widget' => 'single_text'))
->add('save', 'submit');
$options = [
KEY => VALUE,
....
];
if (condition) {
$options = [
ANOTHER_KEY => ANOTHER_VALUE,
....
];
}
$builder->add('task', TYPE, $options);
Another approach would be to use PRE_SUBMIT event, something like this..
$builder
->add('task')
->add('dueDate', null, array('widget' => 'single_text'))
->add('save', 'submit');
$builder->addEventListener(FormEvents::PRE_SUBMIT, [$this, 'preSubmit']);
....
public function preSubmit(FormEvent $event)
{
if (CONDITION) {
$builder->remove('task');
$builder->add('task', TYPE, $NEW_OPTIONS_ARRAY);
}
}
I use this function to update options after a field has been added to a form. It basically means to regenerate the field with the data that we have, add something to the options and re-add the field, re-add its transformers and so
Put this helper function somewhere in a FormHelper class, or wherever you like
/**
* #param FormBuilderInterface $builder
* #param string $fieldName
* #param string $optionName
* #param $optionData
*/
public static function setOptionToExistingFormField(
FormBuilderInterface $builder,
string $fieldName,
string $optionName,
$optionData
): void {
if (!$builder->has($fieldName)) {
// return or throw exception as you wish
return;
}
$field = $builder->get($fieldName);
// Get some things from the old field that we also need on the new field
$modelTransformers = $field->getModelTransformers();
$viewTransformers = $field->getViewTransformers();
$options = $field->getOptions();
$fieldType = get_class($field->getType()->getInnerType());
// Now set the new option value
$options[$optionName] = $optionData;
/**
* Just use "add" again, if it already exists the existing field is overwritten.
* See the documentation of the add() function
* Even the position of the field is preserved
*/
$builder->add($fieldName, $fieldType, $options);
// Reconfigure the transformers (if any), first remove them or we get some double
$newField = $builder->get($fieldName);
$newField->resetModelTransformers();
$newField->resetViewTransformers();
foreach($modelTransformers as $transformer) {
$newField->addModelTransformer($transformer);
}
foreach($viewTransformers as $transformer) {
$newField->addViewTransformer($transformer);
}
}
And then use it like this
$builder
->add('someField', SomeSpecialType::class, [
'label' => false,
])
;
FormHelper::setOptionToExistingFormField($builder, 'someField', 'label', true);
I have a form as below:
class AdminEmployerForm extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('firstName', 'text')
->add('user', new AdminUserForm());
}
}
class AdminUserForm extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('username', 'text')
->add('email', 'text');
}
}
I am calling AdminEmployerForm in controller and I want to remove email field of AdminUserForm from AdminEmployerForm:
$form = $this->createForm(new AdminEmployerForm, $employer);
//i want to do something like $form->remove('email')
how can i do use $form->remove() to remove field in embedded form? Is it possible to remove a field of embedded form from controller?
You'll have to get the embedded form type to remove a field from it.
$form = $this->createForm(new AdminEmployerForm, $employer);
// Get the embedded form...
$adminUserForm = $form->get('user');
// ... remove its email field.
$adminUserForm->remove('email');
Not sure of your exact use-case, but you may consider leveraging form events as it may be more ideal than handling this in the controller.
I'm trying to build a product page that will contain a form with a dynamic number of "options" (either select boxes or input fields) depending on the product. After reading the documentation, I can't see how to create a form entity that would work when building this form. I feel like I'm missing something obvious.
What you need to do is basically create form field of collection type, which will be your collection of select boxes, input fields, whatever.
Check documentation and read about embeding forms, it is described pretty well ther
Your parent form:
class ParentType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('id', 'hidden')
->add('name')
->add('yourCollection', 'collection', array(
'type' => new ChildType(),
'label' => 'Label for your child form',
));
}
}
Your child form:
class ChildType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('id', 'hidden')
->add('category', 'choice')
;
}
}
How to bind data which is gained by using call:
$attributes = $em->getRepository('\OBB\Entity\Attribute')->findAllWithAllRelations($id);
to a Symfony 2 Form
Because according to a manual you need to have a method defined in Entity which is bound to a form.
You should add a form type for editing an individual attribute. This could look something like:
namespace OBB\Form;
class AttributeType extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
$builder->add('name');
}
public function getDefaultOptions(array $options)
{
return array(
'data_class' => 'OBB\Entity\Attribute',
);
}
public function getName()
{
return 'obb_attribute';
}
}
Then you can use a collection form to edit a collection of them simultaneously.
$form = $this->createForm('collection', $attributes, array(
'type' => new AttributeType(),
));