[Django]-How to put JavaScript at the bottom of Django pages when using templatetags?

5👍

I usually have a base template setup like this.

<html>
<head>

{% block js-head %} Tags that need to go up top  {% endblock js-head %}

</head>
<body>
{% block header %}  Header {% endblock header %}

{% block body %} Body goes here {% endblock body %}

{% block footer %}  Footer {% endblock footer %}

{% block js-foot %}  All other javascript goes here {% endblock js-foot %}
</body>
</html>

Then I can extend this base template and only override the blocks that I care about. I put all javascript that doesn’t have to be in the header in js-foot and because it is at the bottom of the template it will load last. If you have have to move where your javascript loads you just need to move the js-foot block around in the base template.

Nothing fancy but it works.

1👍

Wrap the scripts that you’re including inline in

jQuery(function(){ … });

Which will execute when the the DOM is ready and scripts have been downloaded.

Another option might be to create some kind of custom template tag like:

{% inlinescript %}
// some javascript code.
{% endinlinescript %}

Which you could use to aggregate inline scripts as execution proceeds. You’d need aggregate this data as your template gets parsed – which gets tricky because template tags have different contexts and this is something you’d want to store in a global context in a custom variable, say inline_scripts.

I’d look at the way Django implements the various with ... as .. constructs in the default template library for an example of how to add your own variable to a context.

Then at the bottom of your page you could do {{ inline_scripts }}.

The easiest solution is the jQuery.ready(function(){}) / jQuery(function(){ }) (The two methods are synonymous).

Or you might want to reconsider Yahoo’s advice. There are positive things about inlining your javascript – it can reduce FOUC / FOUBC (Flash of unbehavioured content). Yahoo tends to get kind of pedantic – (just look at the YUI API ;). If you need to rewrite parts of your application for what’s going to be moderately perceptible performance improvement, it might not be worth it.


To do the script aggregation (originally based off captureas on django-snippets):

@register.tag(name='aggregate')
def do_aggregate(parser, token):
    try:
        tag_name, args = token.contents.split(None, 1)
    except ValueError:
        raise template.TemplateSyntaxError("'aggregate' node requires a variable name.")
    nodelist = parser.parse(('endaggregate',))
    parser.delete_first_token()
    return AggregateNode(nodelist, args)

class AggregateNode(Node):
    def __init__(self, nodelist, varname):
        self.nodelist = nodelist
        self.varname = varname

    def render(self, context):
        output = self.nodelist.render(context)
        if context.has_key(self.varname):
            context[self.varname] += output
        else:
            context[self.varname] = output
        return ''

Usage:

{% aggregate inline_scripts %}
var foo = 'bar';
{% endaggregate %}

... template code

{% aggregate inline_scripts %}
var baz = 'bar';
{% endaggregate %}

... somewhere near the bottom of your page

{{ inline_scripts }}
👤Koobz

1👍

There is an application django-sekizai just for that

0👍

This worked for me. Wait till the dom loads…

<script>
document.addEventListener("DOMContentLoaded", function (event) {
   {% if my_var %}
      doSomething({{myVar}});
   {% endif %}
});
</script>

Leave a comment