flet-dev / flet

Flet enables developers to easily build realtime web, mobile and desktop apps in Python. No frontend experience required.
https://flet.dev
Apache License 2.0
11.06k stars 428 forks source link

AutoComplete does not work properly or maybe need a documentation #3323

Open caotuan123 opened 4 months ago

caotuan123 commented 4 months ago

Description

Code example to reproduce the issue:

import flet as ft

def main(page: ft.Page):
    auto_complete = ft.AutoComplete(
        suggestions=[
            ft.AutoCompleteSuggestion(key="one 1", value="One"),
            ft.AutoCompleteSuggestion(key="two 2", value="Two"),
            ft.AutoCompleteSuggestion(key="three 3", value="Three"),
        ],
        on_select=lambda e: print(e.selection),
    )
    text_file = ft.TextField(width=400)
    page.add(ft.Row([ft.Column([text_file, auto_complete]), ft.Column([text_file, auto_complete])]))

ft.app(target=main)

image

Describe the results you expected:

I think maybe it should works like a normal TextField.

Additional information you deem important (e.g. issue happens only occasionally):

Flet version (pip show flet):

0.22.1

Give your requirements.txt file (don't pip freeze, instead give direct packages):

(The requirements)

Operating system: Windows

Additional environment details:

Thank you all for such a great library.

Today, I'd like to bring up an issue. I've tried to adjust the width of the AutoComplete component or add a border, but I haven't found a way to do so. Additionally, when I try to combine the AutoComplete component with a TextField in a Row or nested Row/Column (like this: Column[TextField, AutoComplete]), some strange UI issues appear.

hahelui commented 4 months ago

Yeah, same here. I noticed that issue, and now I can't develop my app further because of it. The problem appears to be caused by putting ft.AutoComplete inside an ft.Row. You can put it inside an ft.ResponsiveRow, but it will stretch and expand, leaving no space for the other elements in the same row.

After experimenting more with the widget, I found that you can place it as a child of ft.Stack and change the width of the stack to the desired size. Then, wrap everything inside ft.ResponsiveRow, and it sort of works, but the suggestion's dropdown will not follow the stack size or the widget width.

Screenshot_20240522_090338

However, there's a bigger problem: Sadly, ft.AutoComplete is not supported yet on Android or iOS. I don't know why, maybe the widget is still under development.

Screenshot_20240522-090626 The same problem on IOS

hahelui commented 4 months ago

By the way, this is how I did it if that can help your case: But don't close The Issue because the problems are not fixed yet.

import flet as ft

def main(page: ft.Page):
    list_example = ["one 1", "two 2", "three 3"]
    auto_complete = ft.AutoComplete(
        suggestions=[ft.AutoCompleteSuggestion(value=i) for i in list_example],
        on_select=lambda e: print(e.selection),
    )
    text_file = ft.TextField(width=400)
    page.add(ft.Row([ft.Column([text_file, ft.Stack(controls=[auto_complete],width=400)]),
                                ft.Column([text_file, ft.Stack(controls=[auto_complete],width=400)])]))

ft.app(target=main)
caotuan123 commented 2 months ago

Thank you hahelui it realy helpful. But I think dev team should work on this problem.

ap4499 commented 1 month ago

V0.23. I'm also having this issue. When AutoComplete class is used within a Row(), the suggestions do not behave as expected in the UI.

Putting it within another element (container/column) does not work as a temporary fix to the issue either.

Screenshots: Expected behaviour, where the suggestions are below the widget: Image3

Actual behaviour when used with a row. The suggestions move to the top of the page and obstruct all other elements.: Image2

Row, before entering text: Image1

Code:

import flet as ft
from flet import Page

def main(page:Page):
    suggestions=["Test1","Test2","Test3"]
    some_text = ft.Text(value="Some text")
    Autocomplete_widget = ft.AutoComplete(
                    suggestions=[ft.AutoCompleteSuggestion(value=val) for val in suggestions])

    row = ft.Row(
        controls= [
            some_text,
            Autocomplete_widget
            ]
        )

    page.add(row)

ft.app(target=main)
ap4499 commented 1 month ago

For anyone else that is in a pinch, I've written a custom AutoComplete.

Obviously lacking some of the elegance of a native solution, but it will at least allow you to get similar functionality, whilst using a TextField.

import flet as ft

class CustomAutoComplete_Widget():
    def __init__(self, page, items,col):
        self.page = page
        self.items = items
        self.col = col
        self.filtered_items = items.copy()
        self._build()

    def _build(self):
        self._assets()
        self.stack = ft.Stack(
            controls=[
                self.col,  # Base layer
                self.list_cont,     
            ],
        )
        self.page.add(self.text_field, self.stack)  # Add the stack

    def _assets(self):
        self.list_view = ft.ListView(
            expand=1,
            spacing=10,
            controls=[],
        )
        self.list_cont = ft.Container(
            content = self.list_view,
            bgcolor= ft.colors.WHITE,
        )
        self.text_field = ft.TextField(label="Filter list")
        self.text_field.on_change = self._filter_list

    def _filter_list(self, e):
        query = e.control.value.lower()
        if query:
            self.filtered_items = [item for item in self.items if query in item.lower()]
        else:
            self.filtered_items = []
        self.list_view.controls = [
            ft.ListTile(
                title=ft.Text(item),
                on_click=lambda e, item=item: self._on_list_item_click(item)
            ) for item in self.filtered_items
        ]
        self.page.update()

    def _on_list_item_click(self, item):
        self.text_field.value = item
        self.filtered_items = []
        self.list_view.controls = [] 
        self.page.update()
        print(f"Selected item: {item}") 

def main(page: ft.Page):
    page.title = "Filtered List Example"
    all_items = ["fruit" + str(i) for i in range(1, 101)]

    widget1 = ft.Container(
        bgcolor=ft.colors.YELLOW,
        height=250,
        width=400,
        )

    widget2 = ft.Text("Hello world")

    column = ft.Column(controls= [
        widget1,
        widget2
        ]
    )

    CustomAutoComplete_Widget(page, all_items,column)

ft.app(target=main)