Symfony 3 - EntityType / Dojo - Select Integration
If you use Dojo to provide a polished interface with a Symfony 3 application programmatically, you may use a data- attribute on a select tag to pass the options from Symfony 3 to Dojo.
The entity in this case is phone number type. This is a table with two columns, an id and the type which is a string.
dev=# \d+ phone_number_type Table "public.phone_number_type" Column | Type | Modifiers | Storage | Stats target | Description --------+-----------------------+-----------+----------+--------------+------------- id | integer | not null | plain | | type | character varying(16) | not null | extended | | Indexes: "phone_number_type_pkey" PRIMARY KEY, btree (id) dev=# select * from phone_number_type; id | type ----+----------- 1 | office 2 | home 3 | mobile 4 | alternate 5 | emergency 6 | on-call 7 | other 8 | security (8 rows)
The form uses the entity to allow the user to indicate the type of phone number.
public function buildForm( FormBuilderInterface $builder, array $options )
{
$builder
->add( 'type', EntityType::class, [
'class' => 'AppBundle:PhoneNumberType',
'choice_label' => 'type',
'multiple' => false,
'expanded' => false,
'required' => true,
'choice_translation_domain' => false
] )
->add( 'phonenumber', TextType::class, [
] )
->add( 'comment', TextType::class )
;
}
Next, the twig block is customized to render the options as a data- attribute on the select tag, rather than the options:
{%- block choice_widget_collapsed -%}
{%- if required and placeholder is none and not placeholder_in_choices and not multiple and (attr.size is not defined or attr.size <= 1) -%}
{% set required = false %}
{%- endif -%}
<select {{ block('widget_attributes') }}{% if multiple %} multiple="multiple" {% else %} {% endif %}
{%- if placeholder is not none -%}
{% set blank_value = (placeholder != '') ? (translation_domain is same as(false) ? placeholder : placeholder|trans({}, translation_domain)) %}
{% set blank = { 'value': '', 'label': '{{ blank_value|raw }}'} %}
{%- endif -%}
{%- if preferred_choices|length > 0 -%}
{% set choices = preferred_choices|merge(choices) %}
{%- if choices|length > 0 and separator is not none -%}
{% set choices = choices|merge([{'label':'{{separator}}','disabled':true}]) %}
{%- endif -%}
{%- endif -%}
{%- set options = choices -%}
data-options="{{options|json_encode()}}" data-selected="{% if required and value is empty %}{else}-1{% endif %}">
{%- endblock choice_widget_collapsed -%}
On the client side, the options are read into a MemoryStore
// select is the select node
data = JSON.parse(domAttr.get(select, "data-options"));
// Convert the data to an array of objects
storeData = [];
for( d in data ) {
storeData.push(data[d]);
}
memoryStore = new Memory({
idProperty: "value",
data: storeData});
store = new ObjectStore({objectStore: memoryStore});
typeSelect = new Select({
store: store,
placeholder: core.type,
required: true
}, select);
typeSelect.startup();
This approach is good for cases where there aren't too many options and they are static. If you had a long list, or wanted an autocomplete, an Ajax solution would be better.
A similar approach may be used with other JavaScript libraries and frameworks.
Print article | This entry was posted by elvis on 05/16/16 at 09:13:00 pm . Follow any responses to this post through RSS 2.0. |