views:

346

answers:

2

Here's the way I'm doing it:

{{ formset.management_form }}
<table>
    {% for form in formset.forms %}
        {{ form }}
    {% endfor %}
</table>
<a href="javascript:void(0)" id="add_form">Add Form</a>   

And here's the JS:

var form_count = {{formset.total_form_count}};
$('#add_form').click(function() {
    form_count++;
    var form = '{{formset.empty_form|escapejs}}'.replace(/__prefix__/g, form_count);
    $('#forms').append(form)
    $('#id_form-TOTAL_FORMS').val(form_count);
});

What specifically bothers me is that I had to write that escapejs template tag myself. It just strips all newlines and escapes any single quotes so that it doesn't mess up my string. But what exactly did the Django makers expect us to do in this situation? And why do they have this TOTAL_FORMS hidden field, when they could have just used an array like <input name="my_form_field[0]" /> and then counted its length instead?

+1  A: 

There are a few places in Django where "the reason why" is because that's how it was implemented for the Django admin app, and I believe this is one of them. Thus the answer is they expect you to implement your own javascript.

See this SO question Dynamically adding a form... for some more javascript ideas.

There are also two pluggable apps available, django-dynamic-formset and django-dinamyc-form which I hadn't seen until just now when looking up the first one.

Van Gale
Writing my own JS isn't really a problem... I'm just curious why they would only gave us half the tools we need.... they say the `empty_form` can be used for this, yet it prints with line-breaks and such which isn't very friendly to work with when trying to stuff it into JS, unless I'm misunderstanding something. I think I like my method of dynamic formset better... I suspect it puts less strain on the client, and requires less code :) Oh well... I guess I'm just nitpicking, but I still really disagree with a lot of Django's design decisions.
Mark
Well Django proper design decision is to remain JS-framework neutral. The admin is a contrib app and so technically isn't part of Django core, although some functionality such as formsets (apparently) came from the work on the admin and, while I think the admin is a fine app, it probably does suffer somewhat from lack of a grand design.
Van Gale
+1  A: 

This question is a bit old, but it took me a while to figure this out as well.

I suggest rendering formset.empty_form in your template as a hidden field, and referencing this field in your javascript.

Here's a complicated dynamic formset example from the django admin site: (but note that it has not been updated to use empty_form....)

[js] http://code.djangoproject.com/browser/django/trunk/django/contrib/admin/media/js/inlines.js

[html template] http://code.djangoproject.com/browser/django/trunk/django/contrib/admin/templates/admin/edit_inline/tabular.html

bsk
I recently (a few hours ago actually) redid this... it's really nasty to work with.. to try and add and remove forms, and update all the IDs scattered about, and ensure there's at least one form, and to validate them all properly... combine that with ajax/cascading/contingent select drop downs and it becomes a miniature nightmare.
Mark
Did you work off of the django inlines.js example? I modified it for my site (wanted the add buttons in a separate list). Wasn't trivial (i'm new to js, so it took a while), but I think I managed to contain most of the logic in a single independent script.
bsk