2

In index.html, I link to an index.js file. On click one button, js sends a request to Flask back end. The backend returns a static file path: 'data/Sharon_4.png'. I want to render it in HTML using the following function, but it doesn't work. To simplify it, I replaced the URL with a specific URL as the following, not as a variable. It still doesn't work.

function test(){
    var mvt = document.getElementById('movieThumbnail')
    var ig = document.createElement('img')
    ig.src = `{{url_for('static', filename='data/haron_4.png')}}`

    mvt.append(ig)
}

In HTML the tag seems right <img src="{{url_for('static', filename='data/Sharon_4.png')}}">

If I put this tag directly in HTML or in in-page script, it works. But here using url_for in js it doesns't.

Dark Lei
  • 31
  • 1
  • 7

2 Answers2

4

Jinja2 template processor as commonly employed in Flask apps, only works on template files. You are importing JavaScript via the <script> element. The template processor won't see that JavaScript. If you place JavaScript directly into your HTML file it will be processed by Jinja2. Example:

<script>
function test(){
    var mvt = document.getElementById('movieThumbnail')
    var ig = document.createElement('img')
    ig.src = `{{url_for('static', filename='data/haron_4.png')}}`

    mvt.append(ig)
}
</script>

What you could do is use this simple script to store the static folder in a window variable and use that in your script. Example:

<script>
window.static_folder = "{{url_for('static')}}";
</script>

And then refer to the global var in your script. Crude Example:

function test(){
    const mvt = document.getElementById('movieThumbnail');
    const ig = document.createElement('img');
    ig.src = `${window.static_folder}/data/haron_4.png`;

    mvt.append(ig);
}

Alternative you can call an api on your Flask server to get an url_for. Please see this example:

@bp.route('/url_for/')
def public_get_url_for():
    """
    get the url using the url_for method.  url parameters are given as request args
    ie: /url_for?endpoint=stock_edit&stock_id=12
    example:
    $.get({
                url: '/url_for',
                data: {endpoint: 'stock_edit', stock_id: $('#stock_id').val()}
            }).then(url => window.location = url);

    for route:

    @app.route('/stock_edit/<int:stock_id>')
    def stock_edit(stock_id):
        # some code

    :return: the url or 404 if error
    """
    keywords = request.args.to_dict()
    try:
        return url_for(**keywords)
    except Exception as e:
        return str(e), 404
Martlark
  • 14,208
  • 13
  • 83
  • 99
1

I realize this is now a bit of an old question, but I came across it while investigating whether there was a "flask" way to do this, so I though I'd include how I resolved the problem.

If, like me, your javascript files include a bunch of ajax api calls and you don't want to run the risk of breaking them if you make changes, and you also don't want javascript in every template file or one massive block of inline javascript in the layout template, then this might work for you:

Create a route for the path "/js", that takes a filename as an argument, then returns a render of the filename specified.

from flask import Blueprint, abort, render_template


js = Blueprint('js', __name__, url_prefix='/js')

@js.route('/<filename>', methods=['GET'])
def file(filename):
    # Prevent attempts to go outside of the js directory or return a different type of file
    if "../" in filename or ".js" not in filename:
        abort(404)
    else:
        # Go ahead and try to return the file, if it doesn't exist, return a 404
        try:
            return render_template("js/" + filename)
        except:
            abort(404)

app.register_blueprint(js.js)

Then create a folder called "js" in the templates directory of your flask project, and move all of the javascript files that require jinja to that directory.

/ {root}
|____templates
     |____layout.html
     |____some_other_template.html
          |____js
               |____myJSFile.js

Then in your templates you can use script tags that look like this:

    <script src="{{ url_for('js.file', filename='myJSFile.js') }}" referrerpolicy="origin"></script>

At this point, while they appear in the html output to be being loaded like normal script links, they are actually being loaded as jinja templates, and you can use any jinja you like inside them.

Momus
  • 394
  • 2
  • 13