Search code examples
javascriptjquerydjangoformsdjango-widget

Django; adding variable to media files in a custom widget


I want to make a widget that has some media files, and I want to be able to pass in parameters that the media files have access to.

# in forms.py
class aCustomWidget(forms.TextInput):
    class Media:
        css = {
            'all': ('pretty.css',)
        }
        js = ('animations.js',)

For example, within animation.js I have {{ my_variable }}. My question is, how I could populate {{ my_variable }} inside 'animation.js' in a manner like this:

# in forms.py
class myForm(forms.Form):
    a_field = aCustomWidget(my_variable="#_a_string_variable")

Thank you and feel free to request clarifications.


Solution

  • You can't actually add a variable to the JS file because JS is not parsed like a template. It's static. The only way you can pass a variable in would be to include it in an inline script in the template code:

    <script type="text/javascript">
        var my_variable = '{{ my_variable }}`;
    </script>
    

    However, Django doesn't even use the template parser on widget code. The default render methods return straight ready-to-go HTML. That's not really a problem; you just have to approach it differently.

    So, first, you need to actually be able to accept the variable in the instantiation of the widget. You can do that like so:

    class aCustomWidget(forms.TextInput):
        def __init__(self, *args, **kwargs):
            self.my_variable = kwargs.pop('my_variable')
            super(aCustomWidget, self).__init__(*args, **kwargs)
    

    Then, in your render method, you can access that instance variable to add it to your output:

    from django.utils.safestring import mark_safe
    
    ...
    
    def render(self, name, value, attrs):
        output = super(aCustomWidget, self).render(name, value, attrs)
        if self.my_variable is not None:
            output += u'<script type="text/javascript">var my_variable = "%s";</script>' % self.my_variable
        return mark_safe(output)
    

    Finally, in your JS just utilize that global variable. You'll obviously need to make sure your code runs after the page is done rendering so the variable is available. Also, since you're dealing with a global var here, you should take care with what you name it.