Skip to content

Instantly share code, notes, and snippets.

@npotier
Last active July 15, 2017 02:34
Show Gist options
  • Save npotier/a7b2b34f0daae7205f86 to your computer and use it in GitHub Desktop.
Save npotier/a7b2b34f0daae7205f86 to your computer and use it in GitHub Desktop.
Use the code below to add the "add buton" to a sonata model autocomplete form Raw
<?php
// src/ACSEO/AdminBundle/Admin/ProductAdmin.php
// ...
protected function configureFormFields(FormMapper $formMapper)
{
// ...
$formMapper
->add('codes', 'sonata_type_model_autocomplete', array(
'property' => "name",
'multiple' => true,
'template'=>'ACSEOAdminBundle:Form/Type:sonata_type_model_autocomplete_add.html.twig'
))
// ...
{#
file src/ACSEO/AdminBundle/Resources/views/Form/Type/sonata_type_model_autocomplete_add.html.twig
This file is part of the Sonata package.
(c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
For the full copyright and license information, please view the LICENSE
file that was distributed with this source code.
#}
{% spaceless %}
<input type="text" id="{{ id }}_autocomplete_input" value=""
{%- if read_only %} readonly="readonly"{% endif -%}
{%- if disabled %} disabled="disabled"{% endif -%}
{%- if required %} required="required"{% endif %}
/>
<div id="{{ id }}_hidden_inputs_wrap">
{% if multiple -%}
{%- for idx, val in value if idx~'' != '_labels' -%}
<input type="hidden" name="{{ full_name }}[]" {%- if disabled %} disabled="disabled"{% endif %} value="{{ val }}">
{%- endfor -%}
{% else -%}
<input type="hidden" name="{{ full_name }}" {%- if disabled %} disabled="disabled"{% endif %} value="{{ value[0]|default('') }}">
{% endif -%}
</div>
{# This part is a copy / paste from sonata-project/doctrine-orm-admin-bundle/Resources/views/CRUD/edit_orm_many_to_one.html.twig #}
{% if sonata_admin.edit != 'admin' and sonata_admin.field_description.associationadmin.hasRoute('create') and sonata_admin.field_description.associationadmin.isGranted('CREATE') %}
<a href="{{ sonata_admin.field_description.associationadmin.generateUrl('create', sonata_admin.field_description.getOption('link_parameters', {})) }}"
onclick="return start_field_dialog_form_add_{{ id }}(this);"
class="btn btn-success btn-sm sonata-ba-action"
title="{{"Add" | trans }}"
>
<i class="fa fa-plus-circle"></i>
"{{"Add" | trans }}"
</a>
{% endif %}
{% include 'SonataDoctrineORMAdminBundle:CRUD:edit_modal.html.twig' %}
{% include 'SonataDoctrineORMAdminBundle:CRUD:edit_orm_many_association_script.html.twig' %}
{# end copy / paste #}
<script>
(function ($) {
var autocompleteInput = $('#{{ id }}_autocomplete_input');
autocompleteInput.select2({
{%- set allowClearPlaceholder = (not multiple and not required) ? ' ' : '' -%}
placeholder: '{{ placeholder ?: allowClearPlaceholder }}', // allowClear needs placeholder to work properly
allowClear: {{ required ? 'false' : 'true' }},
enable: {{ disabled ? 'false' : 'true' }},
readonly: {{ read_only ? 'true' : 'false' }},
minimumInputLength: {{ minimum_input_length }},
multiple: {{ multiple ? 'true' : 'false' }},
width: '{{ width }}',
dropdownAutoWidth: {{ dropdown_auto_width ? 'true' : 'false' }},
containerCssClass: '{{ container_css_class ~ ' form-control' }}',
dropdownCssClass: '{{ dropdown_css_class }}',
ajax: {
url: '{{ url ?: path(route.name, route.parameters|default([]))|e('js') }}',
dataType: 'json',
quietMillis: 100,
data: function (term, page) { // page is the one-based page number tracked by Select2
{% block sonata_type_model_autocomplete_ajax_request_parameters %}
return {
//search term
'{{ req_param_name_search }}': term,
// page size
'{{ req_param_name_items_per_page }}': {{ items_per_page }},
// page number
'{{ req_param_name_page_number }}': page,
// admin
{% if sonata_admin.admin is not null %}
'uniqid': '{{ sonata_admin.admin.uniqid }}',
'admin_code': '{{ sonata_admin.admin.code }}',
{% elseif admin_code %}
'admin_code': '{{ admin_code }}',
{% endif %}
{% if context == 'filter' %}
'field': '{{ full_name|replace({'filter[': '', '][value]': '', '__':'.'}) }}',
'_context': 'filter'
{% else %}
'field': '{{ name }}'
{% endif %}
// other parameters
{% if req_params is not empty %},
{%- for key, value in req_params -%}
'{{- key|e('js') -}}': '{{- value|e('js') -}}'
{%- if not loop.last -%}, {% endif -%}
{%- endfor -%}
{% endif %}
};
{% endblock %}
},
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 {% block sonata_type_model_autocomplete_dropdown_item_format %}'<div class="{{ dropdown_item_css_class }}">'+item.label+'<\/div>'{% endblock %};// format of one dropdown item
},
formatSelection: function (item) {
return {% block sonata_type_model_autocomplete_selection_format %}item.label{% endblock %};// 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;
{% if multiple %}
if(!$.isArray(removedItems)) {
removedItems = [removedItems];
}
var length = removedItems.length;
for (var i = 0; i < length; i++) {
el = removedItems[i];
$('#{{ id }}_hidden_inputs_wrap input:hidden[value="'+el.id+'"]').remove();
}
{%- else -%}
$('#{{ id }}_hidden_inputs_wrap input:hidden').val('');
{%- endif %}
}
// add new input
var el = null;
if (undefined !== e.added) {
var addedItems = e.added;
{% if multiple %}
if(!$.isArray(addedItems)) {
addedItems = [addedItems];
}
var length = addedItems.length;
for (var i = 0; i < length; i++) {
el = addedItems[i];
$('#{{ id }}_hidden_inputs_wrap').append('<input type="hidden" name="{{ full_name }}[]" value="'+el.id+'" />');
}
{%- else -%}
$('#{{ id }}_hidden_inputs_wrap input:hidden').val(addedItems.id);
{%- endif %}
}
});
// Initialise the autocomplete
var data = [];
{%- if value is not empty -%}
data = {%- if multiple -%}[ {%- endif -%}
{%- for idx, val in value if idx~'' != '_labels' -%}
{%- if not loop.first -%}, {% endif -%}
{id: '{{ val|e('js') }}', label:'{{ value['_labels'][idx]|e('js') }}'}
{%- endfor -%}
{%- if multiple -%} ] {%- endif -%};
{% endif -%}
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
$('#{{ id }}_autocomplete_input').closest('form').submit(function()
{
$('#{{ id }}_autocomplete_input').remove();
return true;
});
})(jQuery);
</script>
{% endspaceless %}
@ianitsky
Copy link

It returns an error:

The option "template" does not exist. Defined options are:...

@nicolaskern
Copy link

The "add" button can be replaced by "{% trans from 'SonataAdminBundle' %}link_add{% endtrans %}" to keep Sonata's translation

@lushc
Copy link

lushc commented Oct 11, 2016

To preserve the feature of automatically selecting new items created by the add button (so you don't have to search for and select it manually), add the following to the bottom of the closure (line 183):

{% set create_url = sonata_admin.field_description.associationadmin.generateUrl('create', sonata_admin.field_description.getOption('link_parameters', {})) %}

$(document).ajaxSuccess(function(event, xhr, settings) {
  if ('{{ create_url }}'.indexOf(settings.url) !== -1 && typeof xhr.responseJSON != 'string' && xhr.responseJSON.result == 'ok') {
    var form = JSON.parse('{"' + decodeURI(settings.data).replace('+', ' ').replace(/"/g, '\\"').replace(/&/g, '","').replace(/=/g,'":"') + '"}');
    var item = {
      id: xhr.responseJSON.objectId,
      label: form['{{ sonata_admin.field_description.associationadmin.uniqid }}[name]']
    };

    {%- if multiple -%}
      var data = autocompleteInput.select2('data');
      data.push(item);
    {%- else -%}
      var data = item;
    {%- endif -%}

    autocompleteInput.select2('data', data).trigger($.Event('change', {
      val: item.id,
      added: item
    }));
  }
});

@GertjanTillema
Copy link

@lushc: Thank you for the code, this is someting I really miss in my project. But can you give a few more details? I added your code between

                $('#{{ id }}_autocomplete_input').remove();
                return true;
            });

and

        })(jQuery);
    </script>

on line 184. The code is loaded, but nothing happens. How can I test what's wrong?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment