1

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?

blueFast
  • 41,341
  • 63
  • 198
  • 344
  • Is the element ID just the `id` attribute of the generated input, or some server-side ID? – solarissmoke Nov 01 '15 at 03:37
  • @solarissmoke: In this case it is the ID of the generated input, and that is my main interest. Nevertheless I can imagine a use case in which I need to pass arbitrary parameters, so a generic solution would be helpful. – blueFast Nov 01 '15 at 04:51

1 Answers1

1

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'
Community
  • 1
  • 1
solarissmoke
  • 30,039
  • 14
  • 71
  • 73
  • Thanks. This is the exact solution that I am using (selection of all widgets by class), but I thought there was a better way. The idea of using the `data-` attributes to pass extra data is interesting. I'll try that! – blueFast Nov 01 '15 at 05:29