views:

810

answers:

1

I am writing a web application that uses ajax to add new forms on the page. Existing forms are made using inlineformset_factory. When client side gets the form it inserts it in the right position and updates the value of #id_form_type-TOTAL_FORMS" (form_type is name of the form in this example).

Existing forms have name for each field like name="form_type-1-source", where 1 is unique form ID.

The problem is generating next ID for new form so that all forms are different. I have made one solution, but I don't like it.

Url for the ajax call looks like this:

(r'^ajax/get_form/(?P<form_type>\w+)$', views.get_form),

Get form view:

def get_form(request, form_type):
    """
    Returns form for requested model if invoken with ajax.
    If invoken directly returns empty string.

    The form is rendered into HTML using as_p method. 
    """
    if request.method == "GET" and request.is_ajax():
        current_forms_no = int(request.GET["current_forms_no"])
        form_class = all_forms[form_type]
        Formset = inlineformset_factory(Component, form_class.Meta.model, extra=current_forms_no + 1, form = form_class, can_delete = False)
        form = Formset()
        return HttpResponse(form.forms[current_forms_no].as_p())
    else:
        return HttpResponse()

And JavaScript function that invokes that:

function add_new_form(event) {
    event.preventDefault();
    form_type = $(this).attr("href");

    // for id generation
    formset = $("#id_" + form_type + "-TOTAL_FORMS");
    current_forms_no = formset.val()

    container = $(this).parent().parent();
    $.get("/ajax/get_form/" + form_type, {"current_forms_no" : current_forms_no}, function(data) {
     container.append(data);
     container.append("<hr>");

     // increment form count so they can be saved on server
     formset.val(parseInt(formset.val()) + 1);
    })
}

I have more that one form, so functions are generic. I keep form_type in href attribute of anchor.

So, what I am doing here is creating more forms than I need and I only use last of them.

So, is there any way to tell inlineformset_factory what ID I want to be first to generate?

PS: Sorry for my bad English...

+2  A: 

What I did was create an extra form that is hidden, and then simply copy it with Javascript. That is copy the last form, make the hidden form Visible, and hide the new copy of the form.

This way you can just Count the number of forms on the page and use that for you meta Total-Forms variables.

Some fussing will need to be done with DELETED attributes if you want to be able to delete forms on the page. Edit: Here is one of my main functions using prototype js.

function add_form_to_formset(formset, callbacks etc...){
   // Management form
   total_forms_element = $('id_' + formset.prefix + '-TOTAL_FORMS');

   var curr_last_id = biggest_id(formset.form_class);
   var last_form = $('id_' + formset.prefix + '-' + curr_last_id + '-id').up();

   // Copy it
   var new_form = last_form.cloneNode(true);

   ...register some buttons like add/remove etc..

   set_form_id(new_form, curr_last_id+1);

   last_form.show();
   last_form.insert({after:new_form});


   // Increment the management form count
   total_forms_element.value = parseInt(total_forms_element.value) + 1;
drozzy