See https://symfony.com/doc/current/frontend/encore/server-data.html for context.
Twig filter to merge arrays with array_merge_recursive()
instead of array_merge()
. Required to prevent Twig merge
filter from overwritting twig_to_js_global_data string keys if extra_data has identical keys (e.g. both have a translations
key).
Add this to your _base.html.twig, probably just before {% block javascripts %}
{% block twig_to_js_data %}
{% include '_twig_to_js_data.html.twig' %}
{% endblock %}
your_page.html.twig
{# Twig data required by JS on this page is then put in extra_data #}
{% block twig_to_js_data %}
{% include '_twig_to_js_data.html.twig' with {
extra_data: {
csrfTokenYourPage: csrf_token('your_page'),
pathToYourSecondPage: path('your_second_page')
}
} %}
{% endblock %}
Let's say you have Twig global variables defined in config/packages/twig.yaml
twig:
globals:
globals:
global_twig_variable_example_one: 'stuff'
global_twig_variable_example_two: 'stuff2'
_twig_to_js_data.html.twig
{# Put here Twig data required by JS globally on your website (e.g. Google Analytics key) #}
{% set twig_to_js_global_data = {
globalExampleOne: globals.global_twig_variable_example_one,
globalExampleTwo: globals.global_twig_variable_example_two
} %}
{#
IF this template is included in a page and extra_data is defined, merge twig_to_js_global_data with extra_data into one
single twig_to_js_data object.
ELSE just assign twig_to_js_global_data to twig_to_js_data.
#}
{% if extra_data is defined %}
{% set twig_to_js_data = twig_to_js_global_data|array_merge_recursive(extra_data) %}
{% else %}
{% set twig_to_js_data = twig_to_js_global_data %}
{% endif %}
{# JSON encode twig_to_js_data object into a stringified JS object #}
<div id="twig-to-js-data" data-twig-to-js="{{ twig_to_js_data|json_encode }}"></div>
Add to assets/js/app.js
// twig_to_js_data is then parsed into a JS object ready to be used
global.twigData = JSON.parse($('#twig-to-js-data').attr('data-twig-to-js'));
assets/js/views/your-page.js
// Now you can retrieve any of the four examples data.
const globalExampleOne = twigData.globalExampleOne; // Contains 'stuff' string defined in config/packages/twig.yaml
const globalExampleTwo = twigData.globalExampleTwo; // Contains 'stuff2' string defined in config/packages/twig.yaml
const csrfToken = twigData.csrfTokenYourPage; // Contains the string generated by csrf_token('your_page') in templates/your_page.html.twig
const url = twigData.pathToYourSecondPage; // Contains the path generated by path('your_second_page') in templates/your_page.html.twig
Now let's say you want a more complex data structure, maybe because you have a lot of Twig data to pass to JS on a page, your_complex_page.html.twig
{# extra_data can obviously contain objects if you want to have a more complex data structure #}
{% block twig_to_js_data %}
{% include '_twig_to_js_data.html.twig' with {
extra_data: {
csrfTokens: {
yourPageOne: csrf_token('your_page_one'),
yourPageTwo: csrf_token('your_page_two')
},
paths: {
yourSecondPage: path('your_second_page'),
yourThirdPage: path('your_third_page')
},
translations: {
global: {
cancel: 'global.cancel'|trans,
delete: 'global.delete'|trans,
loading: 'global.loading'|trans,
noResult: 'global.no_result'|trans
},
searchBar: {
search: 'search_bar.search'|trans
}
}
}
} %}
{% endblock %}
twigData component structure
- /js
- /components
- /twig-data
- twig-data.js
- /data
- csrf-tokens.js
- paths.js
- translations.js
- /twig-data
- /components
assets/js/components/twig-data/twigData.js
import $ from 'jquery';
export const twigData = JSON.parse($('#twig-to-js-data').attr('data-twig-to-js'));
assets/js/components/twig-data/data/csrf-tokens.js
import {twigData} from '../twig-data';
export const csrfTokens = twigData.csrfTokens;
assets/js/components/twig-data/data/paths.js
import {twigData} from '../twig-data';
export const paths = twigData.paths;
assets/js/components/twig-data/data/translations.js
import {twigData} from '../twig-data';
export const translations = twigData.translations;
assets/js/views/your-complex-page.js
import {csrfTokens} from '../components/twig-data/data/csrf-tokens';
import {paths} from '../components/twig-data/data/paths';
import {translations} from '../components/twig-data/data/translations';
import {twigData} from '../components/twig-data/twigData';
const globalExampleOne = twigData.globalExampleOne; // Contains 'stuff' string defined in config/packages/twig.yaml
const globalExampleTwo = twigData.globalExampleTwo; // Contains 'stuff2' string defined in config/packages/twig.yaml
const csrfTokenYourPageTwo = csrfTokens.yourPageTwo; // Contains the string generated by csrf_token('your_page_two') in templates/your-complex-page.html.twig
const urlToThirdPage = paths.yourThirdPage; // Contains the path generated by path('your_third_page') in templates/your-complex-page.html.twig
const translationGlobaCancel = translations.global.cancel; // Contains the translation generated by 'global.cancel'|trans in templates/your-complex-page.html.twig