2

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.

2
  • As you already thought, you can't pass a JS var to Twig as Twig is already renderd at the serverside before being passed to the client. The only solution here is to switch to ajax and change the style that way Commented Aug 8, 2016 at 15:36
  • So, How can I do this using Ajax? I've try some examples using ajax too and doesn't work. Can you give me an example please? Thanks!! @DarkBee Commented Aug 8, 2016 at 15:43

3 Answers 3

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') }} ">');
Sign up to request clarification or add additional context in comments.

1 Comment

I know that, I wrote it with ´+´ operator in the first example I post, and with ´~´ operator in the second. But the problem is how to use the themeName javascript variable in the Twig code. Thanks for your help
1

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>

5 Comments

Yes, I know all the theme names, but in this last case you are putting a Javascript variable (var themes) into twig code: {% for theme in themes %}. That's not correct. However you gave me an idea: I've try to do this: if (themeName === "blue") { document.write('<link href="{{ asset('bundles/activos/css/app-blue.css') }}" rel="stylesheet" >'); } And so on for every theme name. But here we're back to this problem @DarkBee
With the 2nd example i'm creating a javascript variable from inside twig. Not the other way around, i'm not passing any javascript to twig. I'm just populating a javascript object with known data from twig
Oh ok, sorry I misunderstood. But I've try it and its throws this error in the for line: Variable "themes" does not exist in ::base.html.twig at line 1239. I think I can not use that js variable in that way on the twig 'for'
It's a twig variable.. You need to define and create it in your symfony controller and pass it to twig
Oh ok, now I see your point. I'll do that and try!! Thanks for your time ;)
-1

Strange, the author asked Javascript to be transferred to Twig, but in fact he wanted Twig to be transferred to Javascript? For me it works like this

<script>
   {% set twigVar = 'jsVar' %}
</script>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.