Reputation: 2832
Is there a way to make a fieldset collapsible, but start expanded? When you add collapse to the fieldset classes, it gets the functionality but starts collapsed. I've taken a look at the JS that shows/hides the fieldset content, but it doesn't look like there's anything in there to do what I'd like it to, so I'm assuming I'll have to roll my own. Just wanted to check before I went through that effort.
Upvotes: 21
Views: 22060
Reputation: 19485
django-grappelli provides this as one of the features. Here's the documentation about "Collapsibles".
Upvotes: 4
Reputation: 129
With django 4.x, here is my admin/js/collapse.js add start-open in class
'use strict';
{
window.addEventListener('load', function() {
// Add anchor tag for Show/Hide link
const fieldsets = document.querySelectorAll('fieldset.collapse');
// NEW: select toggles to open
var open_toggles = document.querySelectorAll('fieldset.collapse.start-open');
for (const [i, elem] of fieldsets.entries()) {
// Don't hide if fields in this fieldset have errors
if (elem.querySelectorAll('div.errors, ul.errorlist').length === 0) {
if (elem.classList[3] != 'start-open') {
elem.classList.add('collapsed');
}
const h2 = elem.querySelector('h2');
const link = document.createElement('a');
link.id = 'fieldsetcollapser' + i;
link.className = 'collapse-toggle';
link.href = '#';
if (elem.classList[3] != 'start-open') {
link.textContent = gettext('Show');
} else {
link.textContent = gettext('Hide');
}
h2.appendChild(document.createTextNode(' ('));
h2.appendChild(link);
h2.appendChild(document.createTextNode(')'));
}
}
// Add toggle to hide/show anchor tag
const toggleFunc = function(ev) {
if (ev.target.matches('.collapse-toggle')) {
ev.preventDefault();
ev.stopPropagation();
const fieldset = ev.target.closest('fieldset');
if (fieldset.classList.contains('collapsed')) {
// Show
ev.target.textContent = gettext('Hide');
fieldset.classList.remove('collapsed');
} else {
// Hide
ev.target.textContent = gettext('Show');
fieldset.classList.add('collapsed');
}
}
};
document.querySelectorAll('fieldset.module').forEach(function(el) {
el.addEventListener('click', toggleFunc);
});
});
}
Upvotes: 0
Reputation: 8545
admin.py:
class PageAdmin(admin.ModelAdmin):
fieldsets = (
(None, {
'fields': ('title', 'content', )
}),
('Other Informations', {
'classes': ('collapse', 'open'),
'fields': ('slug', 'create-date',)
}),
)
templates/app_label/model_name/change_form.html:
{% extends "admin/model_name/change_form.html" %}
{% block extrahead %}
{{ block.super }}
<script src="{{ STATIC_URL }}admin/js/collapse-open.js" type="text/javascript"></script>
{% endblock %}
static/admin/js/collapse-open.js:
(function($) {
$(document).ready(function() {
$('fieldset.collapse.open').removeClass('collapsed');
});
})(django.jQuery);
Upvotes: 16
Reputation: 2033
So this one worked for me:
class PageAdmin(admin.ModelAdmin):
fieldsets = (
(None, {
'fields': ('title', 'content', )
}),
('Other Informations', {
'classes': ('wide'),
'fields': ('slug', 'create-date',)
}),
)
Upvotes: 0
Reputation: 1297
The quickest hack I could find was to add a new class start-open
to the fieldset
classes = ['collapse', 'start-open']
and then modify static/admin/js/collapse.js
.
from:
// Add toggle to anchor tag
var toggles = document.querySelectorAll('fieldset.collapse a.collapse-toggle');
var toggleFunc = function(ev) {
ev.preventDefault();
var fieldset = closestElem(this, 'fieldset');
if (fieldset.classList.contains('collapsed')) {
// Show
this.textContent = gettext('Hide');
fieldset.classList.remove('collapsed');
} else {
// Hide
this.textContent = gettext('Show');
fieldset.classList.add('collapsed');
}
};
for (i = 0; i < toggles.length; i++) {
toggles[i].addEventListener('click', toggleFunc);
}
to:
// Add toggle to anchor tag
var toggles = document.querySelectorAll('fieldset.collapse a.collapse-toggle');
// NEW: select toggles to open
var open_toggles = document.querySelectorAll('fieldset.collapse.start-open a.collapse-toggle');
var toggleFunc = function(ev) {
ev.preventDefault();
var fieldset = closestElem(this, 'fieldset');
if (fieldset.classList.contains('collapsed')) {
// Show
this.textContent = gettext('Hide');
fieldset.classList.remove('collapsed');
} else {
// Hide
this.textContent = gettext('Show');
fieldset.classList.add('collapsed');
}
};
for (i = 0; i < toggles.length; i++) {
toggles[i].addEventListener('click', toggleFunc);
}
// NEW: open toggles
for (i = 0; i < open_toggles.length; i++) {
toggles[i].click();
}
Upvotes: 1
Reputation: 334
I know this is real old but I also just came across this issue. After thinking about it way too hard I found an easy solution which seems to get the job done involving 0 plugins or additional js.
Within fieldsets construct Add 'collapse in' rather than 'collapse' to class:
fieldsets = [
('Start Expanded', {
'fields': ['field1', 'field2', 'field3'],
'classes': ['collapse in',]
})
]
Upvotes: 13
Reputation: 1911
Accoding with the grappelli docs only need to add "classes" : ('grp-collapse grp-closed')
for example
class EntryOptions(admin.ModelAdmin):
...
fieldsets = (
('', {
'fields': ('title', 'subtitle', 'slug', 'pub_date', 'status',),
}),
('Flags', {
'classes': ('grp-collapse grp-closed',),
'fields' : ('flag_front', 'flag_sticky', 'flag_allow_comments',),
}),
note: if you use grappelli version < 2.4 use 'grp-closed' instead 'collapse-closed'* actually 'collapse-close' still is working but is recommended to use the new classes
Upvotes: 4
Reputation: 105
Starting from Setomidor answer, I'd like to suggest a simpler alternative that does exactly what you want (if Grappelli is not an option, obviously).
Create the template override as explained (admin/(app)/(model)/change_form.html
) and instead of removing the collapsible effect for the "add" model case, simply call the click method of the field-set collapser (i.e. the small link with the show/hide text) to have the whole field-set expanded as soon as the page loads.
Upvotes: 2
Reputation: 954
Old question, but I ran into the same one and came up with an answer which can be implemented using standard django:
create file: admin/(app)/(model)/change_form.html in your templates directory to make your (model) of your (app) use that form file.
Add this code to the file:
{% extends "admin/change_form.html" %}
{% block extrahead %}
<!-- Load superblock (where django.jquery resides) -->
{{ block.super }}
<!-- only do this on 'add' actions (and not 'change' actions) -->
{% if add and adminform %}
<script type="text/javascript">
(function($) {
$(document).ready(function($) {
//Remove the 'collapsed' class to make the fieldset open
$('.collapse').removeClass('collapsed');
//Remove the show/hide links
$('.collapse h2 a').remove();
//Tidy up by removing the parenthesis from all headings
var $headings = $(".collapse h2");
$headings.each(function(i, current){
var str = $(current).text();
parenthesisStart = str.indexOf('(');
$(current).text(str.substring(0, parenthesisStart));
});
});
})(django.jQuery);
</script>
{% endif %}
{% endblock %}
For more information about using django.jQuery instead of "regular" jQuery, see: http://blog.picante.co.nz/post/Customizing-Django-Admin-with-jQuery--Getting--is-not-a-function/
Upvotes: 0