Load data to Select2 via Ajax in Django


#1

Hi, I am new to Web development. I have been reading through the documents and this thread
Problem with autocomplete with Django Rest API , but still I can’t have data loaded as options.

The doc said both ID and name are needed, but as there’s no ID in my datasource, I pass the name as ID as well.

def get_lvl0(request):
	lv0=levels0()
	lv0_list=[]
	for lv_0 in lv0:
		lv0_list.append({'id':lv_0,'name':lv_0})
	return JsonResponse({'results':lv0_list},safe=False)

And in my http://localhost:8000/get_lvl0, I have

{"results": [{"id": "WA", "name": "WA"}, {"id": "PA", "name": "PA"}, {"id": "TN", "name": "TN"}, {"id": "MD", "name": "MD"}, {"id": "IN", "name": "IN"}, {"id": "DE", "name": "DE"}, {"id": "IL", "name": "IL"}, {"id": "RI", "name": "RI"}, {"id": "VA", "name": "VA"}, {"id": "OK", "name": "OK"}]}

Unlike what’s in the linked thread, http://localhost:8000/get_lvl0?q=WA% does not change anything.

I use below in the client side, but no value loads an options.

<select class="testing" multiple="multiple" name="lv0_es" style="width:30%">
</select>
$(document).ready(function () {
    $('.testing').select2({
        ajax: {
        url: '/get_lvl0',
        dataType: "json",
        type: "GET",
        data: function (params) {
            var queryParameters = {
            q: params.name
        }
            return queryParameters; 
        },
        processResults: function (data) {
            return {
                results: data
            };
        }
},
  placeholder: 'Select a Lv0',
  minimumInputLength: 1
});
});

What am I missing here?


#2

When you say “does not change anything”, what do you mean? If you put http://localhost:8000/get_lvl0?q=WA% directly in your browser’s address bar, what do you get?

It looks like you’re already returning the list of items as the value of the “results” property , which is the correct format, so you don’t need the processResults callback.

Also, your get_lvl0 method currently has no filtering.logic, so regardless of what the user types, their going to get back the entire list.


#3

Thanks for pointing out the missing of no filtering logic. I changed my get_lvl0 below

def get_lvl0(request):
	lv0=levels0()
	lv0_list=[]
	for lv_0 in lv0:
		lv0_list.append({'id':lv_0,'name':lv_0})
	if request.GET.get('q'):
		q=request.GET['q']
		lv0_list=list(filter(lambda d: d['name'] in q, lv0_list))
	return JsonResponse({'results':lv0_list},safe=False)

Now in http://localhost:8000/get_lvl0?q=WA%, I can get

{"results": [{"id": "WA", "name": "WA"}]}

However, I still can not get value on client side (redudant processResults deleted)

<select class="testing" multiple="multiple" name="lv0_es" style="width:30%">
</select>
$(document).ready(function () {
    $('.testing').select2({
        ajax: {
        url: '/get_lvl0',
        dataType: "json",
        type: "GET",
        data: function (params) {
            var queryParameters = {
            q: params.name
        }
            return queryParameters; 
        },
},
  placeholder: 'Select a Lv0',
  minimumInputLength: 1
});
});

#4

So when you type something into the Select2, you get no results? Have you tried watching the network request in the Network tab of your browser’s developer console (F12)? You should see the AJAX request go out after you type two characters, and you should be able to inspect the request and the server’s response.

Try that and let me know what you see. It’s possible there’s some other bug in your code that’s preventing the AJAX call from ever firing. If so, you should see an error in the console, and that might help you troubleshoot the problem.

One other thing: I don’t think you need the data property in your AJAX configuration, since Select2 already sends the user’s search term as the “q” query parameter.


#5

Thanks for explaining on properties and help me understand what I am using.

This is what happened when I type “WA”.Nothing is printed on console. It seems the network is fine?


#6

Oh, I see the problem! Your server-side code is returning the name of the item in the “name” property, but Select2 expects that value in the “text” property. So change “name” to “text” in your server-side code, and that should fix it.


#7

Thank you so much! That’s the problem and it now works.


#8

Great! I’m glad that worked. I’m sorry I didn’t notice the problem sooner.

Good luck with your project!


#9

Thanks John for your great help. I really appreciate it.

I am continuing with my project. The above was intended for a chained drop-down like Populatate a second select based on selection a 1st select except for I hope to have chained drop-down options based on NoSQL database connection

I tried below to get selected Lv0 values but nothing is printed on Chrome console

$('.lv0').on('select2:select', function (e) {
    var data = e.params.data;
    console.log(data); 
});

With above unsolved, I load all Lv1 data like Lv0 to another select box. I find that searching is not working as expected. The dropdown did not return value as the URL.
image


Also, It takes 3+ seconds to fetch a single value

This is the code

$(document).ready(function () {
    $('.lv1').select2({
        ajax: {
        url: '/get_lvl1',
        dataType: "json",
        type: "GET",
},
  placeholder: 'Select a Lv1',
  minimumInputLength: 0
});
});
def get_lvl1(request):
	lv0=""
	print(lv0)
	lv1=levels(lv0)
	print(lv1)
	lv1_list=[]
	lv1_list = list(map(lambda x:{'id':x,'text':x} , list(lv1)))
	if request.GET.get('q'):
		q=request.GET['q']
		lv1_list=list(filter(lambda d: q in d['text'], lv1_list))
	return JsonResponse({'results':lv1_list},safe=False)

Please correct me if I am wrong, I think as full data is loaded in URL already, quicker and better search response can be expected by configuring Select2?


#10

You can get the list of current selections by calling $('.lv0').select2('data');.

As for the 3-second delay to get a result, I have found that if your Select2 has more than a few hundred items, then matching the user’s search term slows down dramatically. I recommend you filter out as much data as you can on the server side, and deliver as few records as possible to the Select2. If that still results in several hundred records then you may want to consider using the pagination feature so only a few results are delivered to the Select2 at one time.