javascriptfilterdjango-formsdropdownchoicefield

How to extend a Django forms ChoiceField to also accept text and search for close matches to avoid having to find something in a long list


I'd like to improve the usability of a form that I have that allows the user to select an area which can be highlighted on a map.

I want to retain the drop-down list for the user to browse but also for them to be able to type in the field as free-text and have a part-match on their input and filter the list to items that resemble their input.

Some of the entry's are quite long and a few words, eg. ideally "Middlesbrough South and East Cleveland" would appear in the list as the user inputs "Cleve" along with any other close matches.

The page looks like this at the moment

I have a simple Django form:-

class ConstituencyForm(forms.Form):
    description = "Use the dropdown to select an area:-"
    lstRandom = [(0, 'Random')]  
    lstChoices = lstRandom + list(constituency.objects.values_list('id', 'name'))
    ConstituencySelection = forms.ChoiceField(choices=lstChoices, widget=forms.Select(),required=False, label="")

The form is instantiated and passed in this extract from the view:-

    frmCons=ConstituencyForm()
    if not request.GET.get("ConstituencySelection") or int(request.GET.get("ConstituencySelection"))==0:
        intConsId = random_cons_view()
        strConsType = "random"
    else:
        intConsId = int(request.GET.get("ConstituencySelection"))
        strConsType = "selected"
    objCons=get_constituency_view(intConsId)

    context={
        "consform" : frmCons,
        "consgeom" : json.loads(objCons[1]),

It appears here in the template:-

    <form method='get' action=''>
        Select an area:-<br>
        {{ context.consform }}<br><br>
        Select a maptile:-<br>
        {{ context.tileform }}<br><br>
        <input type="submit" value="Update" >
    </form>

I'm researching as best as I can, but struggling to piece together how to make this change.

Something like:-
-Change the Form field type to a type that accepts choices and free-text (like a combo field in MS Access)
-Use a filter with "title__contains" in the view? Can I still keep all the choices in the form object?
-Use JavaScript to recognise a key-up event in the field and refresh the list? I'm not at all skilled in JS but would like to give it a go.

What are the steps I need to take and how would it be coded?

Please could you help me to achieve this? Many thanks to a great community,

Phil


Solution

  • I have managed to get something working in the end having taken a course in JS.

    Ultimately, html alone won't get close to combining a select input with a text input in a single control. A combination of a text input right above a select input with appropriate java script events to synchronise the select with what the user types in the text input is close enough in my opinion.

    The event listener responds as follows:-

    On text input keyup (the user is typing looking for a part match) - go through the select options array and set hidden to true or false as the input string develops to increasingly filter the list using a non case-sensitive includes method on each option label. The size property of the select input is also dynamic showing between 1 to a maximum of 5 options based on the options remaining.

    On select input change or click (the user selects an option), a separate read-only text input is set with the value of the selected option and the user can click on a corresponding button to find the data for that option.

    On clicking a clear button: the options in the array have their hidden property reset to false.

    There are a few other bits I added to improve functionality - eg use a regular expression to break a input with punctuation into multiple part matches and look for both but this is contextual for the use-case.

    The code is quite lengthy and bitty so I've attempted to explain this solution contextually assuming appropriate JS knowledge. I'd be happy to provide more detail if anyone has a specific use case they'd like support with.