Adding Javascript to contrib.admin inline fields
This recipe follows on from the last by adding Javascript to the inline fields of a model in the contrib.admin.
Note: this is excerpt a recipe from cleardjango. You can download the source from SVN. Once you've checked it out, do: python tools/configure.py -s 71 to install and run this recipe.
By default the inlines in contrib.admin are a fixed number. In each case Django adds in three extra ingredient inlines for you by default. However, a user may add in more. What we really need is an Javascript solution to add in more rows so the user can keep adding extra rows in one page.
There are two ways to do this. One way is to use the template parameter of the admin.TabularInline. You could add in a new template to display the entire inline field set using this. You’d want to go grab the inline template and then place it in your project to do this. Then you could customize it to add a button and some JavaScript. You can see this in the templates directory of this recipe.
I didn’t choose that way because it involves the copy and paste of large amounts of Django template code. Remember template code can change and you’ll need to maintain that template code across upgrades. The only real advantage of doing that copy and paste is to include a snippet of JavaScript and a bit of HTML. The JavaScript shouldn’t be in the template and should be in an external file anyway. So this is really a less desirable solution.
You’ll see what I chose to do instead in the media folder of this recipe. Take a look at the add_tabular_inline.js file. This uses jQuery to add an add button and then clone the last row of the inlines.
Let’s setup the JavaScript. You can add custom JavaScript using the Media class inside RecipeAdmin. This particular one pulls in jQuery from Google’s servers and then the JavaScript from our recipe [1].
1 2 3 4 5 |
class Media:
js = (
"http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js",
"/recipe_media/add_tabular_inline.js",
)
|
The JavaScript creates a button and then binds a clone event to it. This works with the TabularInline. A StackedInline would require slightly different code. This isn’t much longer at all compared to the embedding in the template version:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
function increment_form_ids(el, to) {
var from = to-1;
$(':input', $(el)).each(function(i,e){
var old_name = $(e).attr('name')
var old_id = $(e).attr('id')
$(e).attr('name', old_name.replace(from, to))
$(e).attr('id', old_id.replace(from, to))
$(e).val('')
})
}
function add_inline_button() {
$(".inline-group p.tools").bind("click", function(e) {
var rows = $(this).parents("div.inline-group").find("tr");
var last = $(rows[rows.length-1]);
var copy = last.clone(true);
if (last.hasClass("row1")) {
copy.attr("class", "row2");
} else {
copy.attr("class", "row1");
}
last.after(copy);
$($(this).parents("div.inline-group").find("input")[0]).val(rows.length);
increment_form_ids(copy, rows.length-1);
return false;
});
}
$(document).ready(add_inline_button);
|
To facilitate the addition and removal of inlines, Django provides an input field that calculates the total number of forms in the formset. When you insert or remove forms, you need to alter that number so that Django knows to process the data. This is the id_recipe-TOTAL_FORMS input. Line 24 of the above code increments that value.
This is based on the work in this blog. [2]
Sponsored Recipe: This recipe was sponsored by Blue Fountain Systems Ltd. Please contact Clearwind if you’d like to sponsor a recipe.
| [1] | See notes in MEDIA_URL and serving static content, something this recipe does on start up. |
| [2] | http://www.arnebrodowski.de/blog/507-Add-and-remove-Django-Admin-Inlines-with-JavaScript.html |
Comments
There are 2 comment(s).
https://www.google.com/accounts/o8/id?id=AItOawmXAD8WzbDGRC_sesEdnr1EbxFKhP2EmVk on Nov, 17I'm seeing some DOM scripting (or dynamic HTML as us old gits used to call it) but I'm not seeing anything that I would describe as Ajax (i.e. using XMLHttpRequest). Not everything that uses JavaScript is Ajax you know...
Login to add comments

