Search code examples
javascriptpythonflaskjinja2

how to link javascript and python variables in jinja2


so suppose that I want to keep track of weather the user has dark mode enabled or not. if it is user's first time, the theme is set to be system preferences.

in my python code, I am simply keeping track of the state. it is set to None by default, since we don't know users settings, yet!

from flask import Flask, render_template

app = Flask(__name__)

state_dark = None

@app.route('/')
def home():
    return render_html('home.html', state_dark = state_dark)

then I have some html and some javascript. the javascript first sets the theme by system preferences. then it has a button to toggle it on and off.

let darkMode = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;

const toggleLightDarkMode = () => {
    darkMode = !darkMode;
    html.setAttribute('data-theme', darkMode ? 'dark' : 'light');
}

as you can see the state_dark variable in python and the darkMode variable in javascript are not linked together at all. I need them to be linked, since some parts of my code work with python and some with javascript. I'd wish if I could do it like this.

let darkMode;
{% if state_dark == None %}
    darkMode = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
{% else %}
    darkMode = {{ state_dark }}
{% endif %}

const toggleLightDarkMode = () => {
    darkMode = !darkMode;
    {{ state_dark }} = darkMode;

    html.setAttribute('data-theme', darkMode ? 'dark' : 'light');
}

I've seen numerous other stack overflow posts about this, but none of them sadly worked. so I would like an answer actually explaining me the solutions to this example.

I see my question has been reported as duplicate, even though I mentioned some stuff above. I understand the gesture, but What is the difference between client-side and server-side programming? doesn't answer my question. I wanna know how to do it in python, not php.


Solution

  • You can use jinja templates and embedded JS inside the HTML Python

    @app.route('/')
    def home():
        return render_html('home.html', state_dark=state_dark)
    

    HTML

    <script>
      let state_dark = "{{state_dark}}"
      let darkMode;
      if (state_dark == "None") {
          darkMode = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
      } else {darkMode = state_dark}
    </script>
    

    To pass data back to Flask, you have to send data using fetch requests.

    JS

    async function sendData(data) {
      await fetch("/send?data="+data)
    }
    

    Flask

    from flask import request
    
    @app.route('/send')
    def recieve():
      global state_dark
      state_dark = request.args.get('data')