django-recurrence icon indicating copy to clipboard operation
django-recurrence copied to clipboard

Avoid inline javascript and allow form media to be loaded after form

Open pigmonkey opened this issue 8 years ago • 0 comments

My templates load form media at the end of the page, after the form itself. In general it seems like loading javascript at the end is still recommended practice for performance. However, this breaks django-recurrence since it uses inline javascript after each form field to load the widget. With the form media not yet loaded, this inline javascript errors out with ReferenceError: recurrence is not defined.

I am working around this problem by ignoring the error and initializing the widgets myself. In my forms I'm defining additional media:

class CourseForm(forms.ModelForm):

    class Meta:
        model = Course
        fields = [...]

    class Media:
        js = [ 'js/recurrence.init.js',]

The js/recurrence.init.js just initializes the widget on every field with a class of recurrence-widget, which forms.RecurrenceWidget conveniently provides:

function loadRecurrenceWidgets() {
    var recurrenceFields = document.querySelectorAll('.recurrence-widget');
    Array.prototype.forEach.call(recurrenceFields, function(field, index) {
        new recurrence.widget.Widget(field.id, {});
    });
}

window.onload = function() {
    loadRecurrenceWidgets();
};

This works fine for me, but I'm wondering if there is some reason why the widgets are not initialized this way by default. The function is called in window.onload, so in addition to avoiding inline javascript, this method should work fine regardless of where the user wants to put {{ form.media }} in their template, which seems ideal.

I'm passing in an empty dictionary for the options because that's what the default behaviour was for my fields. I see js_widget_options defined in forms.RecurrenceWidget, but I'm not sure what it would actually be used for. If this is something that is actively used it seems like it would be preferable for the field widget to add these as data attributes (ie, attrs={'data-recurrence-foo': 'bar'}) which loadRecurrenceWidgets could then pull out of the field element and pass on to the javascript widget builder.

pigmonkey avatar Sep 18 '17 21:09 pigmonkey