Django-dynamic-formset and Chosen

I really like the javascript widget Chosen. I also frequently need to make Django forms with a variable number of associated formsets. To do that, I use django-dynamic-formset. The user clicks “add another” and Django-dynamic-formset clones the last formset to make a new row. It also takes care of updating all the form inputs so that Django accepts these new formsets that magically appeared on the client-side. Conceptually it’s simple and easy. The problem comes when you use complicated widgets in your formset. They do not clone properly.

Chosen is one widget that does not work properly with django-dynamic-formset. Time to start hacking. There are a bunch of possible solutions. First I will present what worked. I layout my formset in a table. The solution that worked for me involved replacing the contents of the table cell with a new, dynamically created select and then associating it with chosen.

First I add the select options to the Django context:

# Django
kwargs['my_options'] = json.dumps([[x.id, unicode(x)] for x in my_queryset])

then in javascript, assign the options to a global var and attach a “added” function to the formset table

var my_options = {{ my_options|safe }};

$('#formset_table').find('.dynamic').formset({
 prefix: '{{ my_formset.prefix }}',
 formCssClass: 'dynamic-formset1',
 added: add_row
});

Next I created a helper function, that creates a function, to replace the contents of the table cell with a new select widget. You can see this code in my Github Gist. Create the actual function in the init part of my javascript:

$(document).ready(function(){
 chosen_fixer = make_fix_chosen_function('.container', '.my_select', my_options);
}

Finally I created the add_row function:

function add_possession_row(row){
   var new_select = chosen_fixer(row);
   new_select.chosen({width: '500px'}).change(changed);
 }

As I mentioned I tried other solutions before I got to this one. First, I noticed the name and id of the cloned select was wrong. So I wrote code to fix that. It was not enough. Next, tried several permutations of this from Stackoverflow. I could not get it to work.

Finally, the major reason to use chosen is when the selects are long. Thus my solution is inefficient because I pass the select data to the client at least two times. It might be possible to improve the efficiency by grabbing the select from an existing input. But I have a deadline and the speed is more than adequate.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s