Browse Source

Adding methods to get computed props (#3395)

* Adding methods to get computed props

Adding methods to get computed props from Quasar elements, using the QTable as a proof of principle

* Adding methods to get computed props

Adding methods to get computed props from Quasar elements, using the QTable as a proof of principle

* Adding methods to get computed props

Adding methods to get computed props from Quasar elements, using the QTable as a proof of principle

* Adding methods to get computed props

Adding methods to get computed props from Quasar elements, using the QTable as a proof of principle

* Adding methods to get computed props

Adding methods to get computed props from Quasar elements, using the QTable as a proof of principle

* code review

* convert async properties into async methods

* make timeout a keyword argument

* add timeout argument to table methods

---------

Co-authored-by: Falko Schindler <falko@zauberzeug.com>
srobertson86 9 months ago
parent
commit
04649ebfd6

+ 12 - 0
nicegui/element.py

@@ -484,6 +484,18 @@ class Element(Visibility):
         return self.client.run_javascript(f'return runMethod({self.id}, "{name}", {json.dumps(args)})',
                                           timeout=timeout, check_interval=check_interval)
 
+    def get_computed_prop(self, prop_name: str, *, timeout: float = 1) -> AwaitableResponse:
+        """Return a computed property.
+
+        This function should be awaited so that the computed property is properly returned.
+
+        :param prop_name: name of the computed prop
+        :param timeout: maximum time to wait for a response (default: 1 second)
+        """
+        if not core.loop:
+            return NullResponse()
+        return self.client.run_javascript(f'return getComputedProp({self.id}, "{prop_name}")', timeout=timeout)
+
     def _collect_descendants(self, *, include_self: bool = False) -> List[Element]:
         elements: List[Element] = [self] if include_self else []
         for child in self:

+ 12 - 0
nicegui/elements/table.py

@@ -226,6 +226,18 @@ class Table(FilterElement, component='table.js'):
             self.selected.clear()
         self.update()
 
+    async def get_filtered_sorted_rows(self, *, timeout: float = 1) -> List[Dict]:
+        """Asynchronously return the filtered and sorted rows of the table."""
+        return await self.get_computed_prop('filteredSortedRows', timeout=timeout)
+
+    async def get_computed_rows(self, *, timeout: float = 1) -> List[Dict]:
+        """Asynchronously return the computed rows of the table."""
+        return await self.get_computed_prop('computedRows', timeout=timeout)
+
+    async def get_computed_rows_number(self, *, timeout: float = 1) -> int:
+        """Asynchronously return the number of computed rows of the table."""
+        return await self.get_computed_prop('computedRowsNumber', timeout=timeout)
+
     class row(Element):
 
         def __init__(self) -> None:

+ 13 - 0
nicegui/static/nicegui.js

@@ -62,6 +62,19 @@ function runMethod(target, method_name, args) {
   }
 }
 
+function getComputedProp(target, prop_name) {
+  if (typeof target === "object" && prop_name in target) {
+    return target[prop_name];
+  }
+  const element = getElement(target);
+  if (element === null || element === undefined) return;
+  if (prop_name in element) {
+    return element[prop_name];
+  } else if (prop_name in (element.$refs.qRef || [])) {
+    return element.$refs.qRef[prop_name];
+  }
+}
+
 function emitEvent(event_name, ...args) {
   getElement(0).$emit(event_name, ...args);
 }

+ 26 - 0
tests/test_table.py

@@ -204,3 +204,29 @@ def test_problematic_datatypes(screen: Screen):
     screen.should_contain('5 days')
     screen.should_contain('(1+2j)')
     screen.should_contain('2021-01')
+
+
+def test_table_computed_props(screen: Screen):
+    all_rows = rows()
+    filtered_rows = [row for row in all_rows if 'e' in row['name']]
+    filtered_sorted_rows = sorted(filtered_rows, key=lambda row: row['age'], reverse=True)
+
+    @ui.page('/')
+    async def page():
+        table = ui.table(
+            columns=columns(),
+            rows=all_rows,
+            row_key='id',
+            selection='multiple',
+            pagination={'rowsPerPage': 1, 'sortBy': 'age', 'descending': True})
+        table.filter = 'e'
+
+        await ui.context.client.connected()
+        assert filtered_sorted_rows == await table.get_filtered_sorted_rows()
+        assert filtered_sorted_rows[:1] == await table.get_computed_rows()
+        assert len(filtered_sorted_rows) == await table.get_computed_rows_number()
+
+    screen.open('/')
+    screen.should_contain('Lionel')
+    screen.should_not_contain('Alice')
+    screen.should_not_contain('Bob')

+ 31 - 0
website/documentation/content/table_documentation.py

@@ -239,6 +239,37 @@ def handle_pagination_changes() -> None:
     )
 
 
+@doc.demo('Computed props', '''
+    You can access the computed props of a table within async callback functions.
+''')
+def computed_props():
+    async def show_filtered_sorted_rows():
+        ui.notify(await table.get_filtered_sorted_rows())
+
+    async def show_computed_rows():
+        ui.notify(await table.get_computed_rows())
+
+    table = ui.table(
+        columns=[
+            {'name': 'name', 'label': 'Name', 'field': 'name', 'align': 'left', 'sortable': True},
+            {'name': 'age', 'label': 'Age', 'field': 'age', 'align': 'left', 'sortable': True}
+        ],
+        rows=[
+            {'name': 'Noah', 'age': 33},
+            {'name': 'Emma', 'age': 21},
+            {'name': 'Rose', 'age': 88},
+            {'name': 'James', 'age': 59},
+            {'name': 'Olivia', 'age': 62},
+            {'name': 'Liam', 'age': 18},
+        ],
+        row_key='name',
+        pagination=3,
+    )
+    ui.input('Search by name/age').bind_value(table, 'filter')
+    ui.button('Show filtered/sorted rows', on_click=show_filtered_sorted_rows)
+    ui.button('Show computed rows', on_click=show_computed_rows)
+
+
 @doc.demo('Computed fields', '''
     You can use functions to compute the value of a column.
     The function receives the row as an argument.