Flask url_for doesn't work in template's external JavaScript

Viewed 1195

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.

1 Answers

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
Related