How to override Symfony form MoneyType input as type="number"?
Asked Answered
B

5

8

The Symfony MoneyType Field renders as input type="text" which allows a user to type whatever they want into the field.

How can I override this to render as input type="number" so that users can only enter numeric characters?

$formBuilder->add("amount", MoneyType::class, [
  'currency' => 'USD'
]);

Current output:

<div><label for="form_amount" class="required">Amount</label>$ <input type="text" id="form_amount" name="form[amount]" required="required"  /></div>

What I am trying to achieve:

<div><label for="form_amount" class="required">Amount</label>$ <input type="number" id="form_amount" name="form[amount]" required="required"  /></div>

I tried to simply override the attribute type, but all this did was add a second type attribute at the end, which didn't work because it's obviously invalid HTML.

$formBuilder->add("amount", MoneyType::class, [
  'attr' => [
    'type' => 'number',
  ],
  'currency' => 'USD'
]);

Here's my simple twig:

{{ form_start(form) }}

    {{ form_widget(form) }}

    <input type="submit" />

{{ form_end(form) }}

I'm also curious, why is this the default input type for Money? I'm considering extending or modifying the class to accommodate this, but I'm sure there's some advantage I'm not seeing.

Bloomington answered 4/7, 2016 at 19:4 Comment(0)
P
2

You can customise how the MoneyType is rendered.

{% extends 'form_div_layout.html.twig' %}

{% block money_widget %}
    {%- set type = type|default('number') -%}
    {{ parent() }}
{% endblock %}

Sources:

http://symfony.com/doc/current/form/form_customization.html#method-2-inside-a-separate-template https://github.com/symfony/symfony/issues/22937#issuecomment-304609466

Pretorius answered 29/5, 2017 at 14:29 Comment(0)
B
3

Why not use 'scale' to specify the number of decimal places, and also use 'placeholder' to tell the user the format:

->add('amount', MoneyType::class, array(
        'label' => 'Enter Amount:',
        'scale' => 2,
        'attr' => array(
                'placeholder' => 'x.xx',
        ),
))

I'm not sure if this is helpful or not.

Edit #2. After getting feedback, i think this should work for you:

use Symfony\Component\Validator\Constraints\Regex;
...

->add('amount', MoneyType::class, array(
        'label' => 'Enter Amount:',
        'scale' => 2,
        'attr' => array(
                'placeholder' => 'x.xx',
        ),
        'constraints' => array(
                new Regex( array( 'pattern' => '/[0-9]{1,}\.[0-9]{2}/')),
        ),
))

See this link for info on adding Validation: http://symfony.com/doc/current/book/forms.html#adding-validation

The above regular expression specifies at least 1 proceeding digit before the decimal, and 2 digits following the decimal place. In your original post you referred to 'currency', but that is a 'string'. You can modify the regular expression based on your needs.

I haven't verified this (I use something similar), but I think it should work.

Biddick answered 4/7, 2016 at 20:41 Comment(5)
Thanks for the answer, but this still allows folks to type in alphabetic characters instead of only numeric ones.Bloomington
Hi, can you specify the format of the input that you need? Then I can give you a much better answer. For example, the format d.dd, where 'd' is a decimal value.Biddick
Two decimal places is great, which is the default. I notice on submission, if it's a valid number, then it truncates it to two decimal places which is fine.Bloomington
I edited my answer - can you try it. This should work.Biddick
This doesn't answer the question. Allowing only numeric input will give a more user friendly keyboard on the mobile phones. Thus, having input=number would be good.Pretorius
P
2

You can customise how the MoneyType is rendered.

{% extends 'form_div_layout.html.twig' %}

{% block money_widget %}
    {%- set type = type|default('number') -%}
    {{ parent() }}
{% endblock %}

Sources:

http://symfony.com/doc/current/form/form_customization.html#method-2-inside-a-separate-template https://github.com/symfony/symfony/issues/22937#issuecomment-304609466

Pretorius answered 29/5, 2017 at 14:29 Comment(0)
R
0

You should be able to override the default field template:

{%- block form_widget_simple -%}
    {%- set type = type|default('text') -%}
    <input type="{{ type }}" {{ block('widget_attributes') }} {% if value is not empty %}value="{{ value }}" {% endif %}/>
{%- endblock form_widget_simple -%}

.... other templates ....

{%- block money_widget -%}
    {{ money_pattern|replace({ '{{ widget }}': block('form_widget_simple') })|raw }}
{%- endblock money_widget -%}

by

{%- block money_widget -%}
    <!-- set your custom html input here -->
{%- endblock money_widget -%}

In a custom template definition

app/Resources/views/form/fields.html.twig

For more information about how to override fields templates see this doc:

http://symfony.com/doc/current/cookbook/form/form_customization.html#method-2-inside-a-separate-template

Rapallo answered 4/7, 2016 at 19:14 Comment(0)
I
0

I had the same issue. When I enter a string in a Money Type field, I had a php "number parsing failed" message.

To solve this I modified intl.error_level value in my php.ini file to 0. You can also comment the line.

No php error anymore. If I enter a string the error is handled by Symfony and I just get the message "This value is not valid" displayed under my input. So no need to override the input type="text"!

Institutor answered 12/7, 2016 at 17:49 Comment(0)
T
0

Had the same issue. You can override the default rendering of the MoneyType field as a string by setting the "html5" option to true and passing the "step" attribute to the "attr" option with the value of ".01" to allow floating point numbers.

Here is an example of how to do this:

$builder->add('amount', MoneyType::class, [
    'label' => 'Amount',
    'scale' => 2,
    'html5' => true,
    'attr' => [
        'step' => '.01',
    ],
]);

Through exploring the MoneyType under the hood you can see what "html5" option is doing:

public function buildView(FormView $view, FormInterface $form, array $options)
{
    $view->vars['money_pattern'] = self::getPattern($options['currency']);

    if ($options['html5']) {
       $view->vars['type'] = 'number';
    }
}

I hope it helps!

Teeny answered 11/5, 2023 at 0:12 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.