Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thibaut-decherit/f644b7e715afd8531c709f4971d2bb16 to your computer and use it in GitHub Desktop.
Save thibaut-decherit/f644b7e715afd8531c709f4971d2bb16 to your computer and use it in GitHub Desktop.
Symfony - Twig to JavaScript Data Passing

Symfony - Twig to JavaScript Data Passing

See https://symfony.com/doc/current/frontend/encore/server-data.html for context.

Requirements

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).

Basic setup

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

Complex setup (recommended)

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

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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment