How to pass a Javascript variable to Twig in this

2019-07-15 01:32发布

问题:

The following code is in my Twig template and it's for load a CSS file or another depending on the theme selected by the user. This works perfectly on a simple HTML page but when I try to take this to the Twig template of my Symfony application I can't find a way to pass the CSS route (with Twig) to the Javascript document.write function.

<script>
var themeSettings = (localStorage.getItem('themeSettings')) ? JSON.parse(localStorage.getItem('themeSettings')) :
        {};
        var themeName = themeSettings.themeName || '';
        if (themeName)
        {
            document.write('<link rel="stylesheet" id="theme-style" href="css/app-' + themeName + '.css">');
        }
        else
        {
            document.write('<link rel="stylesheet" id="theme-style" href="css/app.css">');
        }

In other words: I want to put in the href of the document.write function what (in Twig) it would be this:

<link href="{{ asset('bundles/activos/css/app-red.css') }} "rel="stylesheet" >

Where "app-" is invariable and the word "red" is variable depending on the value of the var themeName

For that I've try this:

<script>
    var themeSettings = (localStorage.getItem('themeSettings')) ? JSON.parse(localStorage.getItem('themeSettings')) :
    {};
    var themeName = themeSettings.themeName || '';
    if (themeName)
    {
    document.write('<link rel="stylesheet" id="theme-style" href="{{  asset('bundles/activos/css/app-' ~ themeName ~ '.css') }} ">');
    }
    else
    {
    document.write('<link rel="stylesheet" id="theme-style" href="{{  asset('bundles/activos/css/app.css') }} ">');
    }
</script>

But it doesn't work, It gave me this error:

Variable "themeName" does not exist in ::base.html.twig at line 1188

I guess it's because themeName is not a Twig variable but a Javascript variable.

I think that the problem here is that I can't pass a Javascript variable to Twig because Javascript is client-side and Twig is server-side. So, how can I solve this problem? Maybe I'm going through the wrong way, maybe using Ajax can be an option, but I don't know how to do it.

回答1:

To concat in javascript you have to use '+' operator

'~' operator is for twig concatenation

document.write('<link rel="stylesheet" id="theme-style" href="{{  asset('bundles/activos/css/app-' + themeName + '.css') }} ">');


回答2:

As you can't pass a javascript variable to twig you will need to fetch the theme uri by ajax.

<!DOCTYPE html>
<html>
    <head>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
        <link rel="stylesheet" id="theme-style" href="{{ asset('bundles/activos/css/app.css') }}">
    </head>
    <body>

        <script>
            $(function() {
                var themeSettings = (localStorage.getItem('themeSettings')) ? JSON.parse(localStorage.getItem('themeSettings')) 
                                                                            : {};
                var themeName = themeSettings.themeName || '';
                if (themeName) {                    
                    $.ajax({
                        url : "url/to/get/theme_uri.php",
                        type: "POST",
                        data : {
                            'themeName' : themeName,
                        },
                        success: function(data, textStatus, jqXHR)
                        {
                            $('#theme-style').attr('href', data.uri);
                        },
                    });
                }
            });
        </script>
    </body>

<?php
    //... This would be a symfony controller
    public function themeUriAction(Request $request){
        $path = 'bundles/activos/css/app-' . $request->request->get('themeName').'.css';
        return new JsonResponse(array('uri' => $this->container->get('templating.helper.assets')->getUrl($path)));
    }
    //...

If you know all the themes at front, you can add them into an array, then you don't need to use ajax

<!DOCTYPE html>
<html>
    <head>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
        <link rel="stylesheet" id="theme-style" href="{{ asset('bundles/activos/css/app.css') }}">
    </head>
    <body>

        <script>

            var themes = {
                {% for theme in themes %}
                    '{{ theme }}': '{{ asset('bundles/activos/css/app-'~theme~'.css') }}',
                {% endfor %}
            };

            $(function() {
                var themeSettings = (localStorage.getItem('themeSettings')) ? JSON.parse(localStorage.getItem('themeSettings'))
                                                                            : {};
                var themeName = themeSettings.themeName || '';
                if (themeName in themes) {
                    $('#theme-style').attr('href', themes[themeName]);
                };
            });
        </script>
    </body>
</html>