Symfony2: How to render HTML5 number input type and accept float values in a form?
I want to use the symfony integer field type because it uses HTML5 "number" input type, which is more assignable for numbers.
When I create my form inside my controller:
$form = $this->createFormBuilder($stuff)
->add('freqLivrLO', 'integer', array(
'label' => 'Fréquence de livraison (nb fois/semaine)',
'rounding_mode'=>null,
'precision'=>2,
'constraints' => array(
new GreaterThan(array(
'value' => 0, 'message' => 'La fréquence de livraison doit être strictement positive')),
new LessThanOrEqual(array(
'value' => 7, 'message' => 'La fréquence de livraison doit être inférieure à 7'))
),
'attr' => array('step'=>'0.01',
'min'=>'0',
'max'=>'7'),
))
Displays a numeric field correctly:
<input id="form_freqLivrLO" name="form[freqLivrLO]" required="required" step="0.01" min="0" max="7" value="0.07" type="number">
However, when I enter a float value, it is rounded to the next available integer. What should I do?
source to share
For now, the only workaround I can find is to create a custom form field type that does not account for the number. Instead of displaying it as text input, I display it as numeric input.
Sources:
- http://symfony.com/doc/current/cookbook/form/create_custom_field_type.html
- http://symfony.com/doc/current/cookbook/form/form_customization.html#cookbook-form-customization-form-themes
Step 1.Creating a custom form field
In your package repository create your own form class (be careful in namespace) FloatType.php
<?php
namespace <Base Bundle Name>\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class FloatType extends AbstractType
{
public function getParent()
{
return 'number';
}
public function getName()
{
return 'float';
}
}
As you can see, your new type simply doesn't inherit from the number type. We'll use it later to cause the form field to display correctly.
Step 2. Creating a template.
To display the newly created form type correctly, you need to call the form template. Since your new type will not contain a number, this will make things much easier.
In the Ressource repository of your package, create a repository called Form inside the view repository. Inside this repository, we'll create a Twig float.html.twig template that will be used to render your custom field:
{% block float_widget %}
{% set type = type|default('number') %}
{{ block('form_widget_simple') }}
{% endblock float_widget %}
Step 3: communication and use
Finally, all that remains is to add your template as a news source in app / config / config.yml
# Twig Configuration
twig:
#use a custom field type for float values
form:
resources:
- '<Bundle full name>:Form:float.html.twig'
And use it in your controller:
use <Base Bundle>\Form\Type\FloatType;
...
$form = $this->createFormBuilder($stuff)
->add('freqLivrLO', new FloatType(), array(
'label' => 'Fréquence de livraison (nb fois/semaine)',
'precision'=>2,
'constraints' => array(
new GreaterThan(array(
'value' => 0, 'message' => 'La fréquence de livraison doit être strictement positive')),
new LessThanOrEqual(array(
'value' => 7, 'message' => 'La fréquence de livraison doit être inférieure à 7'))
),
'attr' => array('step'=>'0.01',
'min'=>'0',
'max'=>'7'),
))
And this! Any better solution would be greatly appreciated: D
source to share
By receiving signals from Adambey, you can:
->add('lat', NumberType::class, array (
'required' => true,
'scale' => 7,
'attr' => array(
'min' => -90,
'max' => 90,
'step' => 0.0000001,
),
))
In your Twig template you will need to define the type, and in my case it looks like this:
{{ form_widget(edit_form.lat, { 'type':'number' }) }}
source to share
I got around this by using a little cheeky JQuery to change the input type at runtime.
Here is my form entry:
->add('totalDays', 'number', array(
'required' => false,
'scale' => 1,
'attr' => array(
'_type' => "number",
'min' => 0,
'step' => 0.5,
),
))
Now here's my JQuery will change the input type to whatever was defined in the "_type" attribute:
$('input').each(function(k, v){
if ($(this).attr('_type')) {
$(this).prop('type', $(this).attr('_type'));
}
});
source to share