3

I'm asking you for a litte advice in creating specific form in Symfony 3.

After reading Symfony Docs I have some solution in mind, but I'm asking you for sharing best aproach to achieve this.

I need to get output form like this: link for expected example form

As you see i need to make single field constiting of one checkbox and one input type. It should work like if user ticks the checkbox, the input will be active.

Should it be custom field with getParent() method from FormType as parent? Maybe this form should be created dynamically with event listener and some Javascript? Or it should be CollectionType field (but how it can store two different form field types?) or maybe you know different solution?

Basically one field should consist of two different field type depending from each other.

Any help, sharing knowledge or some code examples will be very welcome.

1 Answer 1

4

First, you have to build a custom FormType that composes a CheckboxType and a TextType. This is the server-side form part.

But, in order to enable/disable the text field on the fly, you'll have to use Javascript.

Finally, if you want to store the result information a single nullable text field (like a nullable varchar), you need a DataTransformer to convert data from persistece layer to view.

Let's see a kind of FormType :

<?php

namespace Form\Type;

use Form\DataTransformer\NullableTextTransformer;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;

class NullableTextType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('isNotNull', CheckboxType::class)
            ->add('text', TextType::class, array('required' => false))
        ;

        $builder->addModelTransformer(new NullableTextTransformer());
    }
}

And now the transformer :

<?php

namespace Form\DataTransformer;

use Symfony\Component\Form\DataTransformerInterface;

class NullableTextTransformer implements DataTransformerInterface
{
    public function transform($value)
    {
        $nullableText = ['isNotNull' => false, 'text' => null];

        if (null !== $value) {
            $nullableText['isNotNull'] = true;
            $nullableText['text'] = (string) $value;
        }

        return $nullableText;
    }

    public function reverseTransform($array)
    {
        if (!is_array($array) || empty($array) || !isset($array['isNotNull']) || !isset($array['text'])) {
            return;
        }

        if ($array['isNotNull']) {
            return (string) $array['text'];
        } else {
            return;
        }
    }
}

Some twig for the form theming of the custom field :

{% block nullable_text_widget %}
{% spaceless %}
  <div class="input-group nullable-text-widget">
    <div class="input-group-addon">
      {{ form_widget(form.isNotNull, {attr: {class: 'is-not-null-widget'}}) }}
    </div>
    {{ form_widget(form.text, {attr: {class: 'text-widget'}}) }}
  </div>
{% endspaceless %}
{% endblock nullable_text_widget %}

And finally, a bunch of JS lines to handle the front interactions :

$(document).ready(function() {
    $.each($('body').find('.nullable-text-widget'), function () {
        syncNullableTextWidget($(this));
    });
});

$(document).on('click', '.nullable-text-widget .is-not-null-widget', function (e) {
    var $nullableTextWidget = $(e.currentTarget).parents('.nullable-text-widget');
    syncNullableTextWidget($nullableTextWidget);
});

function syncNullableTextWidget($widget)
{
    if ($widget.find('.is-not-null-widget').prop('checked')) {
        $widget.find('.text-widget').prop('disabled', false);
    } else {
        $widget.find('.text-widget').prop('disabled', true);
        $widget.find('.text-widget').val('');
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

Great answer! Thank you!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.