Django Admin - RelatedObjectLookups - How Does it refresh and set the select on the parent window?
I want one of my forms to work just like the admin page does so I figured I'd look in the code and see how it works.
Specifically I want the user to be able to click a "+" icon next to a select list and be taken to the admin page's popup form to add a new item.
When they enter a new item there,开发者_运维技巧 I want that new item to appear in the select box, and be selected (Just like how this feature works on the admin pages).
I copied the admin js libraries into my own template, and I made my link call the same JS function and the popup windows does open correctly, but after I save a new object the popup window goes blank instead of closing, and nothing happens on the parent page.
Here's what I put in my page:
...
<td>
<div class="fieldWrapper">
<select name="form-0-plasmid" id="id_form-0-plasmid">
...
</select>
<a href="/admin/VirusTracker/plasmid/add/" class="add-another" id="add_id_plasmid" onclick="return showAddAnotherPopup(this);"> <img src="/media/admin/img/admin/icon_addlink.gif" width="10" height="10" alt="Add Another"/></a>
</div>
</td>
...
I tried stepping through the javascript on the admin form to see how it's working, but I'm not seeing anything that would close the window or populate the parent window's select.
Thanks in advance for any help.
Update 3
I'm getting this javascript error when dismissAddAnotherPopup is run
"SelectBox is not defined"
Which is pointing to this line in dismissAddAnotherPopup
SelectBox.add_to_cache(toId, o);
I thought I knew Javascript, but I don't see where that variable is supposed to come from :-(
Update 2
Everything seems to be firing properly. After I click save on the popup window I get a blank page. This is the source of that page:
<script type="text/javascript">opener.dismissAddAnotherPopup(window, "9", "CMV_flex_myr_GENE1_._._WPRE_BGH");</script>
So it would seem that this javascript isn't being executed or is failing.
Update
Here is the relevant code that Daniel mentioned. So the only problem is that this code either isn't firing, or is firing incorrectly.
django/contrib/admin/options.py:
...
if request.POST.has_key("_popup"):
return HttpResponse('<script type="text/javascript">opener.dismissAddAnotherPopup(window, "%s", "%s");</script>' % \
# escape() calls force_unicode.
(escape(pk_value), escapejs(obj)))
...
/media/admin/js/admin/RelatedObjectLookups.js:
function dismissAddAnotherPopup(win, newId, newRepr) {
// newId and newRepr are expected to have previously been escaped by
// django.utils.html.escape.
newId = html_unescape(newId);
newRepr = html_unescape(newRepr);
var name = windowname_to_id(win.name);
var elem = document.getElementById(name);
if (elem) {
if (elem.nodeName == 'SELECT') {
var o = new Option(newRepr, newId);
elem.options[elem.options.length] = o;
o.selected = true;
} else if (elem.nodeName == 'INPUT') {
if (elem.className.indexOf('vManyToManyRawIdAdminField') != -1 && elem.value) {
elem.value += ',' + newId;
} else {
elem.value = newId;
}
}
} else {
var toId = name + "_to";
elem = document.getElementById(toId);
var o = new Option(newRepr, newId);
SelectBox.add_to_cache(toId, o);
SelectBox.redisplay(toId);
}
win.close();
}
Ok, the javascript simply uses the id attribute of the launching element to identify the select field to update. (after removing 'add_' from the beginig).
So I simply changed the link's id attribute to match the select element's id in my template:
<a href="/admin/VirusTracker/plasmid/add/" class="add-another" id="add_id_{{field.html_name}}" onclick="return showAddAnotherPopup(this);"> <img src="/media/admin/img/admin/icon_addlink.gif" width="10" height="10" alt="Add Another"/></a>
Wow I wish this had been documented somewhere! I lost a few hours on this.
(See my updates to the question for more technical details on how it all works.)
The trick - and it's a bit of a hack, actually - is what happens when you click save on the popup in the admin.
If you look at the code of response_add
in django.contrib.options.ModelAdmin
, you'll see that when you save an item in the popup, the admin returns an HttpResponse consisting solely of a piece of Javascript. This JS calls the dismissAddAnotherPopup
function in the parent window, which closes the popup and sets the form value appropriately.
It's fairly simple to copy this functionality into your own app.
Edited after updates If admin javascript doesn't work, it's usually because it has a dependency on the jsi18n
code - which you include via a URL (not a static path):
<script type="text/javascript" src="/admin/jsi18n/"></script>
I was having the same problem refreshing the select in the parent window, and I solved following this doc
Everything is working fine now
Edit 1:
I was trying to use Select2 to make the select pretty, the single select works fine, the multiple select is giving me headaches for some reason is not updating the info in the parent form.
Anyone tried this before?
精彩评论