Преглед изворни кода

Enable freetext input in select, address #1045

Artem Revenko пре 1 година
родитељ
комит
1c241eb044
2 измењених фајлова са 60 додато и 2 уклоњено
  1. 21 2
      nicegui/elements/select.py
  2. 39 0
      tests/test_select.py

+ 21 - 2
nicegui/elements/select.py

@@ -17,6 +17,7 @@ class Select(ChoiceElement, DisableableElement, component='select.js'):
                  with_input: bool = False,
                  multiple: bool = False,
                  clearable: bool = False,
+                 add_new_unique_values: bool = False,
                  ) -> None:
         """Dropdown Selection
 
@@ -31,6 +32,7 @@ class Select(ChoiceElement, DisableableElement, component='select.js'):
         :param with_input: whether to show an input field to filter the options
         :param multiple: whether to allow multiple selections
         :param clearable: whether to add a button to clear the selection
+        :param add_new_unique_values: allow to add new unique values, equivalent to `new-value-mode="add-unique"`. Is only applied if `with_input == True`.
         """
         self.multiple = multiple
         if multiple:
@@ -47,6 +49,8 @@ class Select(ChoiceElement, DisableableElement, component='select.js'):
             self._props['hide-selected'] = not multiple
             self._props['fill-input'] = True
             self._props['input-debounce'] = 0
+            if add_new_unique_values:
+                self._props['new-value-mode'] = 'add-unique'
         self._props['multiple'] = multiple
         self._props['clearable'] = clearable
 
@@ -63,11 +67,26 @@ class Select(ChoiceElement, DisableableElement, component='select.js'):
         if self.multiple:
             if e.args is None:
                 return []
-            return [self._values[arg['value']] for arg in e.args]
+            else:
+                out = []
+                for arg in e.args:
+                    if isinstance(arg, str):
+                        self.options.append(arg)
+                        self.update()
+                        out.append(self._values[len(self.options) - 1])
+                    else:
+                        out.append(self._values[arg['value']])
+                return out
         else:
             if e.args is None:
                 return None
-            return self._values[e.args['value']]
+            else:
+                if isinstance(e.args, str):
+                    self.options.append(e.args)
+                    self.update()
+                    return self._values[len(self.options) - 1]
+                else:
+                    return self._values[e.args['value']]
 
     def _value_to_model_value(self, value: Any) -> Any:
         # pylint: disable=no-else-return

+ 39 - 0
tests/test_select.py

@@ -1,3 +1,5 @@
+from selenium.webdriver import Keys
+
 from nicegui import ui
 
 from .screen import Screen
@@ -32,6 +34,10 @@ def test_select_with_input(screen: Screen):
     screen.should_contain('AB')
     screen.should_not_contain('XYZ')
 
+    screen.find_by_tag('input').send_keys('ABC' + Keys.ENTER)
+    screen.find_by_tag('input').click()
+    screen.should_not_contain('ABC')
+
 
 def test_replace_select(screen: Screen):
     with ui.row() as container:
@@ -86,3 +92,36 @@ def test_set_options(screen:  Screen):
     screen.click('4')
     screen.should_contain('5')
     screen.should_contain('6')
+
+
+def test_add_new_values(screen:  Screen):
+    ui.select(
+        with_input=True,
+        options=['1', '2', '3'],
+        add_new_unique_values=True
+    )
+    screen.open('/')
+    screen.find_by_tag('input').send_keys('123' + Keys.TAB)
+    screen.wait(0.5)
+    screen.find_by_tag('input').click()
+    screen.should_contain('123')
+
+
+def test_add_new_values_with_multiple(screen:  Screen):
+    l = ui.label()
+    s = ui.select(
+        with_input=True,
+        options=['1', '2', '3'],
+        value='1',
+        multiple=True,
+        add_new_unique_values=True
+    ).props('use-chips')
+    l.bind_text_from(s, 'value', backward=str)
+    screen.open('/')
+    screen.should_contain("['1']")
+    screen.find_by_tag('input').send_keys('123' + Keys.ENTER)
+    screen.wait(0.5)
+    screen.find_by_tag('input').click()
+    screen.should_contain('123')
+    screen.click('123')
+    screen.should_contain("['1', '123']")