django-autocomplete-light
django-autocomplete-light copied to clipboard
Option to select all matching entries in multi selects
Hi again :) I would like to be able to select all matching entries, tried using code from https://github.com/select2/select2/issues/195#issuecomment-240130634 (jsbin showing it), but when I use it, no options previously inside form are listed. Any simple way to make it work, or that's more complicated issue?
Edit: Thrown the code inside the form template, if that's relevant.
It works for me when I select "California", then open select2 again and click "Select All". It moved a bit, but it's there. How to reproduce your issue exactly ?
I tried to use it on modelform which has 2 autocomplete fields. Person, that is directly taken from model and Report, that queries reports based on person chosen. JS is simply dumped to this form template js section. When I'll be back home I'll try to reproduce it on test project.
The same behavior can be observed in test project - added script to select2_gm2m template: https://github.com/marekjedrzejewski/django-autocomplete-light/commit/3cb7006577221d75dd8fb8ac24a09d69edb04e0b and 'select all' button appears within form fields, but options are no longer there.
@jpic Did you have any chance to look at this?
Any insight on this? :)
I needed this implemented with ajax(because of the large select options). Here is my overly hacky/completed solution for this:
In form field i keep the default widget and don't use dal widget. Also I set the queryset to none since I will be using the ajax to get the items.
forms.py
terms = ModelMultipleChoiceField(
queryset=Term.objects.none(),
required=False,
# widget=autocomplete.ModelSelect2(url='dove:term_autocomplete')
)
Difference in view class is that I set the paginate_by to a high number so I don't have to deal with pagination.
views.py
class TermAutocomplete(autocomplete.Select2QuerySetView):
paginate_by = 1000
def get_queryset(self):
# Don't forget to filter out results depending on the visitor !
if not self.request.user.is_authenticated:
return Term.objects.none()
qs = Term.objects.all()
if self.q:
qs = qs.filter(label__icontains=self.q)
return qs
In javascript:
- I manually initiate the select2 on the select field.
- We get objects with ajax call. However objects when displayed in select2 dropdown don't have their pk.
- Using the select2 templateResult I added back object pk to dropdown li elements.
- After search is made I added at the top of the search field a "Select All" button.
- Since there are no options in select we add the options using the pk's we added with template.
- select them all using .val()
function formatResult(r) {
return $('<span id="select2-result-id-' + r.id + '">' + r.text + '</span>');
}
$("#id_terms").select2({
minimumInputLength: 3,
templateResult: formatResult,
ajax: {
url: "{% url 'dove:term_autocomplete' %}",
dataType: 'json',
cache: false,
// Additional AJAX parameters go here; see the end of this chapter for the full code of this example
}
});
var terms_search_field = $("#id_terms").data("select2").$selection.find('.select2-search__field');
var terms_label = $("#geneset-form-div")[0].querySelector("label[for='id_terms']")
terms_label.innerHTML += '<button type="button" id="clear-all-terms">Clear All</button>'
$("#clear-all-terms")[0].addEventListener("click", function(){
$("#id_terms").val(null).trigger("change");
});
terms_search_field[0].addEventListener("keyup", function(){
if (terms_search_field.val().length >= 3) {
var results = $("#select2-id_terms-results")[0];
if (!results.innerHTML.includes("select-all-matched-terms")) {
results.innerHTML = '<li><button type="button" id="select-all-matched-terms">Select All</button></li>' + results.innerHTML
}
$("#select-all-matched-terms")[0].addEventListener("click", function(){
var matches = [];
$.each($(".select2-results__options").find('li'), function(i, item) {
var term_id = item.children[0].id.split("-").splice(-1)[0];
var term_text = item.children[0].textContent;
if (term_id.length > 0 && term_id != "terms"){
if ($('#id_terms').find("option[value='" + term_id + "']").length) {
$('#id_terms').val(term_id).trigger('change');
} else {
// Create a DOM Option and pre-select by default
var newOption = new Option(term_text, term_id, true, true);
// Append it to the select
$('#id_terms').append(newOption).trigger('change');
}
matches.push(term_id);
}
});
$("#id_terms").val(matches).trigger("change");
terms_search_field[0].value = "";
$("#id_terms").select2("close");
});
}
// Do something
});
Lastly since we set the queryset to none at the begining django won't accept the values. To solve this we set the queryset to all in the POST forms init function.
form.py
def __init__(self, post=False, *args, **kwargs):
super(GeneSetForm, self).__init__(*args, **kwargs)
if post:
self.fields['terms'].queryset = Term.objects.all()
Initiate the form class with post True.
views.py
` form = GeneSetForm(True, request.POST)``