yourlabs / django-autocomplete-light

A fresh approach to autocomplete implementations, specially for Django. Status: v4 alpha, v3 stable, v2 & v1 deprecated.
https://django-autocomplete-light.readthedocs.io
MIT License
1.79k stars 467 forks source link

Allow free text in Select2ListView #1264

Open guanana opened 2 years ago

guanana commented 2 years ago

Hello here! :)

I'll expose my case as detailed as possible:

I'm using the functionality of autocomplete to automatically populate a value that is dynamic into the form. The form has several values, when you fill the first 3 I'm able to run an operation (with those values) and return a suggested value to the user. I needed to adapt a bit the return of parameters but I achieved it with Select2ListView

class MyFunctionAutocomplete(autocomplete.Select2ListView):
    def get_list(self):
        if not self.request.user.is_authenticated:
            return [""]
        try:
            field1_pk = self.forwarded["field1"]
            field2_pk = self.forwarded["field2"]
            field3_pk = self.forwarded["field3"]
        except AttributeError:
            return [""]
        try:
            ObjField1 = ModelField1.objects.get(pk=field1_pk)
            ObjField2 = ModelField2.objects.get(pk=field2_pk)
            ObjField3 = ModelField3.objects.get(pk=field3_pk)
            return_value = ObjField1.get_result(param1=ObjField2, param2=ObjField3")
        except (ModelField1.DoesNotExist, ModelField2.DoesNotExist, ModelField3.DoesNotExist):
            return [""]
        return [return_value]

With this code I'm able to do what I need when the requirements (forwarded value) are present. So far, so good

My problem: I cannot ADD any value as an extra option. This value IS NOT a ForeignKey, it's a simple Float. I want the user to be able to use my suggested value or instead just replace it by another value of their choice. Let's say in the dropdown they have the value 3.22221 and they want to write 12.11.

Since it can be practically ANY value I was thinking free text makes sense (I'll take care of cleaning data if necessary later). I checked and it looks like https://select2.org/tagging is what I want but not sure if I can use it here.

My form field in the form in case that helps is like:

result_field = Select2ListCreateChoiceField(
        widget=autocomplete.Select2(
            url="myapp:result_field_autocomplete",
            forward=["field1", "field2", "field3"],
            attrs={"data-container-css-class": ""},
        ),
        help_text=constants.RESULT_HELP,
)

Desired functionality:

result_field = Select2ListCreateChoiceField(
        widget=autocomplete.Select2(
            url="myapp:result_field_autocomplete",
            forward=["field1", "field2", "field3"],
            attrs={"data-container-css-class": ""},
            **free_text=True,**
        ),
        help_text=constants.RESULT_HELP,
)

And that the flag will allow me to enter ANY text of my choice.

I can get somewhere by changing the widget to TaggingSelect2 but that for sure it's not the option, is clumsy and the user will have multiple option which is NOT what I want.

Ideally all I would need (if someone can think of another option) is the info to appear as initial data in the form once I filled the other 3 elements by running that function. If that can be done with just another method it will be great as well.

I hope it makes sense :)

gamesbook commented 2 years ago

I am not the dev/owner here, but my sense is that you're trying to make one thing do too much. An alternative option is simply to provide another, free text field on your form and then check in the form handling that the user has filled in one (and only one) of these two fields.

guanana commented 2 years ago

Mmm maybe you're right but tbh I kind of expect this kind of functionality to be possible. And it looks like it maybe (since changing it to tagging widget make it work). I was hoping it would be an easy add-on or even something that I'm missing (even that before posting I made sure to read the docs fully and even parts of the code)

syshq commented 2 years ago

I know what you need. I need the same thing. The oldschool select2 supports it. It's the first example on this page https://select2.org/tagging. It basically creates an option and selects it when not present, if you hit enter after typing. Let us know if you work it out.

n1ngu commented 2 years ago

Pretty much related https://github.com/yourlabs/django-autocomplete-light/issues/1111#issuecomment-534023106

I apology because I thought I'd contribute the widget and I never did.

Just add the queried value in the return list

def get_list(self):
  # ...
  return self.q + [return_value]