Search code examples
javascriptdjangodjango-formsdjango-widget

How to pass parameters to widget js asset?


It is possible to pass custom js to a widget, as explained in the documentation. In my case, the custom js is this:

function setUpImagePreview(inputId, imgId) {
...
}

window.onload = function() {
    // IDs hardcoded, VERY BAD! How to solve this?
    setUpImagePreview('id_brand_logo', id_brand_logo_img');
};

I am using this to control some effects on a forms.FileField. The important thing here is that the IDs are related to the specific field that I am rendering. There will be possibly more than one such field in a form, so I need to be able to:

  • pass the element IDs (id_brand_logo and id_brand_logo_img) to the script
  • run the script for each Widget, not just once for the whole page

Is this possible to achieve with django Widgets / Forms?


Solution

  • Making some assumptions about what your requirements are, my suggestion is that your JS should rely only on the HTML generated by your widget.

    Assume you render every widget inside some predefined class .my-widget-class (your question on how to do this). Then you can find all inputs in the DOM using the normal JS query selector methods (document.querySelectorAll('.my-widget-class')) or a library like jQuery, and perform whatever manipulation you require.

    Any arbitrary data that needs to be sent from the server can be sent as data attributes specified in the form field/widget, e.g.:

    class MyForm(forms.Form):
        brand_logo = forms.FileField(widget=ClearableFileInput) # Or some custom widget
        brand_logo.widget.attrs['data-something'] = 'custom-data-here'
    

    ... which you can access in the DOM using the standard JS getAttribute method.

    If it is a ModelForm and you need to pass some instance-related information to the widget, then you would need to perform this step inside the form's __init__ method after it has been bound to the model instance:

    class MyForm(forms.Form):
    
        def __init__(self, *args, **kwargs):
            super(MyForm, self).__init__(*args, **kwargs)
            # Check if the form is bound to an instance first
            if hasattr(self, 'instance'):
                self.fields['brand_logo'].widget.attrs['data-something'] = 'custom-data-here'