SonataAdminBundle: Required sonata_type_model_autocomplete causing "An invalid form control with name='' is not focusable"

Environment

Sonata packages

$ composer show sonata-project/*
sonata-project/admin-bundle              3.4.0  The missing Symfony Admin G...
sonata-project/block-bundle              3.1.1  Symfony SonataBlockBundle
sonata-project/cache                     1.0.7  Cache library
sonata-project/classification-bundle     3.1.0  Symfony SonataClassificatio...
sonata-project/core-bundle               3.0.3  Symfony SonataCoreBundle
sonata-project/datagrid-bundle           2.2    Symfony SonataDatagridBundle
sonata-project/doctrine-extensions       1.0.2  Doctrine2 behavioral extens...
sonata-project/doctrine-orm-admin-bundle 3.0.5  Symfony Sonata / Integrate ...
sonata-project/easy-extends-bundle       2.1.10 Symfony SonataEasyExtendsBu...
sonata-project/exporter                  1.5.0  Lightweight Exporter library
sonata-project/intl-bundle               2.2.4  Symfony SonataIntlBundle
sonata-project/media-bundle              3.1.0  Symfony SonataMediaBundle
sonata-project/notification-bundle       3.0.0  Symfony SonataNotificationB...

Symfony packages

$ composer show symfony/*
symfony/assetic-bundle     v2.8.0  Integrates Assetic into Symfony2
symfony/monolog-bundle     2.11.1  Symfony MonologBundle
symfony/polyfill-apcu      v1.2.0  Symfony polyfill backporting apcu_* func...
symfony/polyfill-intl-icu  v1.2.0  Symfony polyfill for intl's ICU-related ...
symfony/polyfill-mbstring  v1.2.0  Symfony polyfill for the Mbstring extension
symfony/polyfill-php54     v1.2.0  Symfony polyfill backporting some PHP 5....
symfony/polyfill-php55     v1.2.0  Symfony polyfill backporting some PHP 5....
symfony/polyfill-php56     v1.2.0  Symfony polyfill backporting some PHP 5....
symfony/polyfill-php70     v1.2.0  Symfony polyfill backporting some PHP 7....
symfony/polyfill-util      v1.2.0  Symfony utilities for portability of PHP...
symfony/security-acl       v3.0.0  Symfony Security Component - ACL (Access...
symfony/swiftmailer-bundle v2.3.11 Symfony SwiftmailerBundle
symfony/symfony            v2.8.8  The Symfony PHP framework

PHP version

$ php -v
PHP 7.0.9 (cli) (built: Jul 21 2016 08:19:58) ( NTS )
Copyright (c) 1997-2016 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2016 Zend Technologies
    with Zend OPcache v7.0.9, Copyright (c) 1999-2016, by Zend Technologies
    with Xdebug v2.4.0, Copyright (c) 2002-2016, by Derick Rethans

Subject

First of all this could be related to #1994 and #3446 but the first one was never marked as fixed and the former has a commit that should have fix it but still getting the same error message.

I have some sonata_type_model_autocomplete fields in an admin entity that fail to validate correctly in Chrome (52 right now) when trying to create a new entity from Sonata Admin. This problem only happens with fields marked as required, for example:

class BusinessAdmin extends BaseAdmin
{
    // Fields to be shown on create/edit forms
    protected function configureFormFields(FormMapper $formMapper)
    {
        $formMapper
...
                ->add(
                    'city',
                    'sonata_type_model_autocomplete',
                    array(
                        'label' => 'admin.label.city',
                        'required' => true,
                        'multiple' => false,
                        'property' => 'name',
                    )
                )
...
                ->add(
                    'categories',
                    'sonata_type_model_autocomplete',
                    array(
                        'required' => true,
                        'multiple' => true,
                        'property' => 'name',
                        'to_string_callback' => function($entity, $property) {
                            return $entity->getName().' (ID: '.$entity->getId().')';
                        },
                        'callback' => function ($admin, $property, $value) use ($parentCategory) {
                            // Show only child categories from "Businesses" category
                            $datagrid = $admin->getDatagrid();
                            $queryBuilder = $datagrid->getQuery();
                            $queryBuilder
                                ->andWhere($queryBuilder->getRootAlias() . '.parent=:parentCategory')
                                ->setParameter('parentCategory', $parentCategory->getId())
                            ;
                            $datagrid->setValue($property, null, $value);
                        },
                    )
                )
    }
}

There is another not required (and multiple) sonata_type_model_autocomplete field in the same admin entity that does not arise the issue:

            ->add(
                'users',
                'sonata_type_model_autocomplete',
                array(
                    'required' => false,
                    'multiple' => true,
                    'label' => 'admin.label.users',
                    'property'=>'username',
                )
            )

This is the generated HTML+Java Script in the form for one off the affected fields (I know it’s messy and I’m sorry but it may help debug the issue):

<div class="form-group" id="sonata-ba-field-container-s5798adf90f5a1_city">




                    <label class="control-label required" for="s5798adf90f5a1_city">
                            Ciudad
                    </label>



        <div class="sonata-ba-field sonata-ba-field-standard-natural">
                <div class="select2-container form-control" id="s2id_s5798adf90f5a1_city_autocomplete_input"><a href="javascript:void(0)" class="select2-choice" tabindex="-1">   <span class="select2-chosen" id="select2-chosen-1">Vitoria-Gasteiz</span><abbr class="select2-search-choice-close"></abbr>   <span class="select2-arrow" role="presentation"><b role="presentation"></b></span></a><label for="s2id_autogen1" class="select2-offscreen"></label><input class="select2-focusser select2-offscreen" type="text" aria-haspopup="true" role="button" aria-labelledby="select2-chosen-1" id="s2id_autogen1"></div><input type="text" id="s5798adf90f5a1_city_autocomplete_input" value="" required="required" tabindex="-1" title="" style="display: none;"><div id="s5798adf90f5a1_city_hidden_inputs_wrap"><input type="hidden" name="s5798adf90f5a1[city]" value="2715"></div><script>
        (function ($) {
            var autocompleteInput = $('#s5798adf90f5a1_city_autocomplete_input');
            autocompleteInput.select2({placeholder: '', // allowClear needs placeholder to work properly
                allowClear: false,
                enable: true,
                readonly: false,
                minimumInputLength: 3,
                multiple: false,
                width: '',
                dropdownAutoWidth: false,
                containerCssClass: ' form-control',
                dropdownCssClass: '',
                ajax: {
                    url:  '\x2Fapp_dev.php\x2Fadmin\x2Fcore\x2Fget\x2Dautocomplete\x2Ditems',
                    dataType: 'json',
                    quietMillis: 100,
                    cache: false,
                    data: function (term, page) { // page is the one-based page number tracked by Select2
                                                return {
                                //search term
                                'q': term,

                                // page size
                                '_per_page': 10,

                                // page number
                                '_page': page,

                                // admin
                                                                    'uniqid': 's5798adf90f5a1',
                                    'admin_code': 'sonata.admin.business',

                                 // subclass

                                                                    'field':  'city'

                                // other parameters
                                                        };
                                            },
                    results: function (data, page) {
                        // notice we return the value of more so Select2 knows if more results can be loaded
                        return {results: data.items, more: data.more};
                    }
                },
                formatResult: function (item) {
                    return '<div class="">'+item.label+'<\/div>';// format of one dropdown item
                },
                formatSelection: function (item) {
                    return item.label;// format selected item '<b>'+item.label+'</b>';
                },
                escapeMarkup: function (m) { return m; } // we do not want to escape markup since we are displaying html in results
            });

            autocompleteInput.on('change', function(e) {

                // console.log('change '+JSON.stringify({val:e.val, added:e.added, removed:e.removed}));

                // remove input
                if (undefined !== e.removed && null !== e.removed) {
                    var removedItems = e.removed;

                    $('#s5798adf90f5a1_city_hidden_inputs_wrap input:hidden').val('');                }

                // add new input
                var el = null;
                if (undefined !== e.added) {

                    var addedItems = e.added;

                    $('#s5798adf90f5a1_city_hidden_inputs_wrap input:hidden').val(addedItems.id);                }
            });

            // Initialise the autocomplete
            var data = [];if (undefined==data.length || 0<data.length) { // Leave placeholder if no data set
                autocompleteInput.select2('data', data);
            }

            // remove unneeded autocomplete text input before form submit
            $('#s5798adf90f5a1_city_autocomplete_input').closest('form').submit(function()
            {
                $('#s5798adf90f5a1_city_autocomplete_input').remove();
                return true;
            });
        })(jQuery);
    </script> 

                    </div>
    </div>

Steps to reproduce

Add a sonata_type_model_autocomplete field linked to another entity with required set to true. Open the create new entity form in Sonata Admin and don’t select a related object for that field. Click on “Create”.

Expected results

The required fields should be focused and labeled with the browsers own validate message “Please fill this out this field” (if you are using Chrome, other browser will have another text message).

Actual results

A JavaScript error with this message in the console:

[Sonata.Admin] [core|show_form_first_tab_with_errors] show first tab with errors, [object Object]
create:1 An invalid form control with name='' is not focusable.

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Reactions: 4
  • Comments: 27 (15 by maintainers)

Most upvoted comments

I think I have this issue for every EntityType::class field (and maybe more Type, maybe ChoiceType too). The User can’t submit the page without having any error message, since the required field has display: none.

I have to put all my field as required: false and use validation constraint. That’s not the best.

I’ll take a look if I can fix this.

I needed a quick solution:

.sonata-ba-field.sonata-ba-field-standard-natural select[tabindex='-1']{
    display:block !important;
    width: 0.1px !important;
    height: 0.1px !important;
    opacity: 0.01 !important;
}

I think I’ve narrowed it down a little bit. The autocomplete input is being rendered with select2, and it has a non visible input field (with a style="display:none") were the actual selected value is placed, AFAIK this is how select2 works internaly. As I made my field in the form required the browser tries to validate it but as it is non visible it’s also non focusable, thus the error. If I make this input field visible (removing the style with the inspector once the page is loaded) it shows the usual “Please fill out this field” when “Create” is clicked and the error is gone, but of course the input field is shown bellow the select2 widget.

screen shot 2016-07-29 at 11 23 32

Here you can see the input that gives the problem selected in blue (with the style already removed):

screen shot 2016-07-29 at 11 24 27

I ran into this problem. Same situation. A ManyToMany association, using ModelAutocompleteType, and a “required” => true in the form type options.

From what I can tell, the input that is selected from the ‘#{{ id }}_autocomplete_input_v4’ is correctly removed. There is another input that is ‘#{{ id }}_autocomplete_input’ (same but without the v4) that is required and is unfocusable. Built-in browser validation can’t focus the required form element, which prevents the form from being submitted and doesn’t provide a useful error message.

Yes sure, I’ll do a step by step debugging as soon as I have a break at work. Just so I can go straight to the point, do you know which JavaScript file and/or function is called when any of the “Create” buttons are clicked?