Eel
Eel copied to clipboard
Implementation of Jinja2 Variables
First of all : Eel is amazing ! This is a project I'd love to participate with.
One of the features I find lacking is the implementation of Jinja Variables. While the documentation and the options allow for inserting and using templates (with the jinja_templates
argument in the start()
function), I did not see any possibility to transfer variables within the templates.
It would be nice if this could be included either as a decorator or in a more "flask-like" fashion in the return of a function.
One solution that I tried to fiddle with but to no avail, was to create a decorator for the _static
function (in the __init__.py
) that seems to handle Jinja's template.render()
function.
Here's what I got so far:
def jinjaVariables(_static):
def innerFunction(path, jinja_variable=None):
# the decorator recieved a Jinja Variable
if "jinja_variables" is not None:
response = None
if 'jinja_env' in _start_args and 'jinja_templates' in _start_args:
template_prefix = _start_args['jinja_templates'] + '/'
if path.startswith(template_prefix):
n = len(template_prefix)
template = _start_args['jinja_env'].get_template(path[n:])
response = btl.HTTPResponse(template.render(jinja_variable))
if response is None:
response = btl.static_file(path, root=root_path)
_set_response_headers(response)
return response
_static(path)
return innerFunction
The idea was to create a global dictionary variable called jinja_variable
and to update that variable depending on the page you want to visit.
If you were to include the jinja_variable
in the kwargs
of the start()
function, wouldn't it be possible to dynamically change the output of the html page by accessing the required keys ?
Hey @Nootaku - thanks for your interest in Eel!
You're definitely right that the implementation of jinja templating is a little lacking here, and being able to pass variables into the render calls does limit its utility.
I'd love to understand your use-case a little better so we can start to work out the best way forward. At the moment I'm not sure I understand your proposed solution or that it works for a general case. I'll start to have a think about it, but any details you can provide will help me understand where you're coming from.
Thanks!
Hey @samuelhwilliams - thank you for your swift answer.
I'm am a relatively inexperienced programmer, so the code above was simply something that I thought could be possible to integrate in the framework.
I'll try to be as short as possible, but here is my thought process:
- Based on what Flask does, it is possible to nest Jinja's
template.render()
function inside flask'srender_template()
function (see templating.py line 116 to 141). This means the arguments of Flask'srender_template()
function are being passed on to Jinja'stemplate.render()
function. - Currently Eel does something similar in its
_static()
function. - This means that it should be possible to modify the
_static()
function as follows (or something similar)
def _static(path, **context):
"""Arguments:
- path: path to the jinja template
- context: dictionary with
key = jinja variable name
value = jinja variable value
"""
response = None
if (
'jinja_env' in _start_args and
'jinja_templates' in _start_args
):
template_prefix = _start_args['jinja_templates'] + '/'
if path.startswith(template_prefix):
n = len(template_prefix)
template = _start_args['jinja_env'].get_template(path[n:])
if context is not None:
response = btl.HTTPRespons(
template.render(context)
)
else:
response = btl.HTTPRespons(
template.render()
)
if response is None:
response = btl.static_file(path, root=root_path)
_set_response_headers(response)
return response
- By doing this, the last problem we are facing is to provide the
**context
argument to_static()
in a way that is possible for the user to send variable for each html-page he/she wants to load. To do so, I have two options that come to mind:- the use of a decorator
- create an independant function
In both cases, taking Eel's structure in consideration, we should pass 2 arguments:
- a path_to_template
- the context_dictionary
I believe it might end up looking something like this (and it is what I tried to make last week):
@eel.jinja_variables(some_context_dictionary)
def load_template(path_to_template):
html_page = eel.render_page(path_to_template, some_context_dictionary)
return html_page
Cheers
It's making building html in for-loops waaaay cleaner.
I would just pass an object to the template and get the values in a for-loop. But for Eel, I have to get the values in a for-loop, run the python command from javascript and do another for-loop for building the html.
And putting in values in html is in jinja itself muuch fancier.
There's some update on this topic? I'm falling in love with this project and having the possibility to pass context to jinja would be super helpfull
So am I correct in understanding that you can't pass a python variable to jinja or for example a data table?
I also hope this will be implemented, before or (probably) later! 👯
Hello, would it be possible to implement that, please? Just change of 1-2 lines of code in init.py is required:
Line 245 before:
response = btl.HTTPResponse(template.render())
Line 245 after:
response = btl.HTTPResponse(template.render(_start_args['jinja_context']))
And then optionally add 'jinja_context': None
to _start_args
on line 53