1
0

table_documentation.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  1. from nicegui import ui
  2. from . import doc
  3. @doc.demo(ui.table)
  4. def main_demo() -> None:
  5. columns = [
  6. {'name': 'name', 'label': 'Name', 'field': 'name', 'required': True, 'align': 'left'},
  7. {'name': 'age', 'label': 'Age', 'field': 'age', 'sortable': True},
  8. ]
  9. rows = [
  10. {'name': 'Alice', 'age': 18},
  11. {'name': 'Bob', 'age': 21},
  12. {'name': 'Carol'},
  13. ]
  14. ui.table(columns=columns, rows=rows, row_key='name')
  15. @doc.demo('Omitting columns', '''
  16. If you omit the `columns` parameter, the table will automatically generate columns from the first row.
  17. Labels are uppercased and sorting is enabled.
  18. *Updated in version 2.0.0: The `columns` parameter became optional.*
  19. ''')
  20. def omitting_columns():
  21. ui.table(rows=[
  22. {'make': 'Toyota', 'model': 'Celica', 'price': 35000},
  23. {'make': 'Ford', 'model': 'Mondeo', 'price': 32000},
  24. {'make': 'Porsche', 'model': 'Boxster', 'price': 72000},
  25. ])
  26. @doc.demo('Default column parameters', '''
  27. You can define default column parameters that apply to all columns.
  28. In this example, all columns are left-aligned by default and have a blue uppercase header.
  29. *Added in version 2.0.0*
  30. ''')
  31. def default_column_parameters():
  32. ui.table(rows=[
  33. {'name': 'Alice', 'age': 18},
  34. {'name': 'Bob', 'age': 21},
  35. ], columns=[
  36. {'name': 'name', 'label': 'Name', 'field': 'name'},
  37. {'name': 'age', 'label': 'Age', 'field': 'age'},
  38. ], column_defaults={
  39. 'align': 'left',
  40. 'headerClasses': 'uppercase text-primary',
  41. })
  42. @doc.demo('Selection', '''
  43. You can set the selection type of a table using the `selection` parameter.
  44. The `on_select` event handler is called when the selection changes
  45. and the `selected` property contains the selected rows.
  46. *Added in version 2.11.0:*
  47. The `selection` property and the `set_selection` method can be used to change the selection type.
  48. ''')
  49. def selection():
  50. table = ui.table(
  51. columns=[{'name': 'name', 'label': 'Name', 'field': 'name'}],
  52. rows=[{'name': 'Alice'}, {'name': 'Bob'}, {'name': 'Charlie'}],
  53. row_key='name',
  54. on_select=lambda e: ui.notify(f'selected: {e.selection}'),
  55. )
  56. ui.radio({None: 'none', 'single': 'single', 'multiple': 'multiple'},
  57. on_change=lambda e: table.set_selection(e.value))
  58. @doc.demo('Table with expandable rows', '''
  59. Scoped slots can be used to insert buttons that toggle the expand state of a table row.
  60. See the [Quasar documentation](https://quasar.dev/vue-components/table#expanding-rows) for more information.
  61. ''')
  62. def table_with_expandable_rows():
  63. columns = [
  64. {'name': 'name', 'label': 'Name', 'field': 'name'},
  65. {'name': 'age', 'label': 'Age', 'field': 'age'},
  66. ]
  67. rows = [
  68. {'name': 'Alice', 'age': 18},
  69. {'name': 'Bob', 'age': 21},
  70. {'name': 'Carol'},
  71. ]
  72. table = ui.table(columns=columns, rows=rows, row_key='name').classes('w-72')
  73. table.add_slot('header', r'''
  74. <q-tr :props="props">
  75. <q-th auto-width />
  76. <q-th v-for="col in props.cols" :key="col.name" :props="props">
  77. {{ col.label }}
  78. </q-th>
  79. </q-tr>
  80. ''')
  81. table.add_slot('body', r'''
  82. <q-tr :props="props">
  83. <q-td auto-width>
  84. <q-btn size="sm" color="accent" round dense
  85. @click="props.expand = !props.expand"
  86. :icon="props.expand ? 'remove' : 'add'" />
  87. </q-td>
  88. <q-td v-for="col in props.cols" :key="col.name" :props="props">
  89. {{ col.value }}
  90. </q-td>
  91. </q-tr>
  92. <q-tr v-show="props.expand" :props="props">
  93. <q-td colspan="100%">
  94. <div class="text-left">This is {{ props.row.name }}.</div>
  95. </q-td>
  96. </q-tr>
  97. ''')
  98. @doc.demo('Show and hide columns', '''
  99. Here is an example of how to show and hide columns in a table.
  100. ''')
  101. def show_and_hide_columns():
  102. from typing import Dict
  103. columns = [
  104. {'name': 'name', 'label': 'Name', 'field': 'name', 'required': True, 'align': 'left'},
  105. {'name': 'age', 'label': 'Age', 'field': 'age', 'sortable': True},
  106. ]
  107. rows = [
  108. {'name': 'Alice', 'age': 18},
  109. {'name': 'Bob', 'age': 21},
  110. {'name': 'Carol'},
  111. ]
  112. table = ui.table(columns=columns, rows=rows, row_key='name')
  113. def toggle(column: Dict, visible: bool) -> None:
  114. column['classes'] = '' if visible else 'hidden'
  115. column['headerClasses'] = '' if visible else 'hidden'
  116. table.update()
  117. with ui.button(icon='menu'):
  118. with ui.menu(), ui.column().classes('gap-0 p-2'):
  119. for column in columns:
  120. ui.switch(column['label'], value=True, on_change=lambda e,
  121. column=column: toggle(column, e.value))
  122. @doc.demo('Table with drop down selection', '''
  123. Here is an example of how to use a drop down selection in a table.
  124. After emitting a `rename` event from the scoped slot, the `rename` function updates the table rows.
  125. ''')
  126. def table_with_drop_down_selection():
  127. from nicegui import events
  128. columns = [
  129. {'name': 'name', 'label': 'Name', 'field': 'name'},
  130. {'name': 'age', 'label': 'Age', 'field': 'age'},
  131. ]
  132. rows = [
  133. {'id': 0, 'name': 'Alice', 'age': 18},
  134. {'id': 1, 'name': 'Bob', 'age': 21},
  135. {'id': 2, 'name': 'Carol'},
  136. ]
  137. name_options = ['Alice', 'Bob', 'Carol']
  138. def rename(e: events.GenericEventArguments) -> None:
  139. for row in rows:
  140. if row['id'] == e.args['id']:
  141. row['name'] = e.args['name']
  142. ui.notify(f'Table.rows is now: {table.rows}')
  143. table = ui.table(columns=columns, rows=rows).classes('w-full')
  144. table.add_slot('body-cell-name', r'''
  145. <q-td key="name" :props="props">
  146. <q-select
  147. v-model="props.row.name"
  148. :options="''' + str(name_options) + r'''"
  149. @update:model-value="() => $parent.$emit('rename', props.row)"
  150. />
  151. </q-td>
  152. ''')
  153. table.on('rename', rename)
  154. @doc.demo('Table from Pandas DataFrame', '''
  155. You can create a table from a Pandas DataFrame using the `from_pandas` method.
  156. This method takes a Pandas DataFrame as input and returns a table.
  157. ''')
  158. def table_from_pandas_demo():
  159. import pandas as pd
  160. df = pd.DataFrame(data={'col1': [1, 2], 'col2': [3, 4]})
  161. ui.table.from_pandas(df).classes('max-h-40')
  162. @doc.demo('Table from Polars DataFrame', '''
  163. You can create a table from a Polars DataFrame using the `from_polars` method.
  164. This method takes a Polars DataFrame as input and returns a table.
  165. *Added in version 2.7.0*
  166. ''')
  167. def table_from_polars_demo():
  168. import polars as pl
  169. df = pl.DataFrame(data={'col1': [1, 2], 'col2': [3, 4]})
  170. ui.table.from_polars(df).classes('max-h-40')
  171. @doc.demo('Adding rows', '''
  172. It's simple to add new rows with the `add_row(dict)` and `add_rows(list[dict])` methods.
  173. With the "virtual-scroll" prop set, the table can be programmatically scrolled with the `scrollTo` JavaScript function.
  174. ''')
  175. def adding_rows():
  176. from datetime import datetime
  177. def add():
  178. table.add_row({'date': datetime.now().strftime('%c')})
  179. table.run_method('scrollTo', len(table.rows)-1)
  180. columns = [{'name': 'date', 'label': 'Date', 'field': 'date'}]
  181. table = ui.table(columns=columns, rows=[]).classes('h-52').props('virtual-scroll')
  182. ui.button('Add row', on_click=add)
  183. @doc.demo('Custom sorting and formatting', '''
  184. You can define dynamic column attributes using a `:` prefix.
  185. This way you can define custom sorting and formatting functions.
  186. The following example allows sorting the `name` column by length.
  187. The `age` column is formatted to show the age in years.
  188. ''')
  189. def custom_formatting():
  190. columns = [
  191. {
  192. 'name': 'name',
  193. 'label': 'Name',
  194. 'field': 'name',
  195. 'sortable': True,
  196. ':sort': '(a, b, rowA, rowB) => b.length - a.length',
  197. },
  198. {
  199. 'name': 'age',
  200. 'label': 'Age',
  201. 'field': 'age',
  202. ':format': 'value => value + " years"',
  203. },
  204. ]
  205. rows = [
  206. {'name': 'Alice', 'age': 18},
  207. {'name': 'Bob', 'age': 21},
  208. {'name': 'Carl', 'age': 42},
  209. ]
  210. ui.table(columns=columns, rows=rows, row_key='name')
  211. @doc.demo('Toggle fullscreen', '''
  212. You can toggle the fullscreen mode of a table using the `toggle_fullscreen()` method.
  213. ''')
  214. def toggle_fullscreen():
  215. table = ui.table(
  216. columns=[{'name': 'name', 'label': 'Name', 'field': 'name'}],
  217. rows=[{'name': 'Alice'}, {'name': 'Bob'}, {'name': 'Carol'}],
  218. ).classes('w-full')
  219. with table.add_slot('top-left'):
  220. def toggle() -> None:
  221. table.toggle_fullscreen()
  222. button.props('icon=fullscreen_exit' if table.is_fullscreen else 'icon=fullscreen')
  223. button = ui.button('Toggle fullscreen', icon='fullscreen', on_click=toggle).props('flat')
  224. @doc.demo('Pagination', '''
  225. You can provide either a single integer or a dictionary to define pagination.
  226. The dictionary can contain the following keys:
  227. - `rowsPerPage`: The number of rows per page.
  228. - `sortBy`: The column name to sort by.
  229. - `descending`: Whether to sort in descending order.
  230. - `page`: The current page (1-based).
  231. ''')
  232. def pagination() -> None:
  233. columns = [
  234. {'name': 'name', 'label': 'Name', 'field': 'name', 'required': True, 'align': 'left'},
  235. {'name': 'age', 'label': 'Age', 'field': 'age', 'sortable': True},
  236. ]
  237. rows = [
  238. {'name': 'Elsa', 'age': 18},
  239. {'name': 'Oaken', 'age': 46},
  240. {'name': 'Hans', 'age': 20},
  241. {'name': 'Sven'},
  242. {'name': 'Olaf', 'age': 4},
  243. {'name': 'Anna', 'age': 17},
  244. ]
  245. ui.table(columns=columns, rows=rows, pagination=3)
  246. ui.table(columns=columns, rows=rows, pagination={'rowsPerPage': 4, 'sortBy': 'age', 'page': 2})
  247. @doc.demo('Handle pagination changes', '''
  248. You can handle pagination changes using the `on_pagination_change` parameter.
  249. ''')
  250. def handle_pagination_changes() -> None:
  251. ui.table(
  252. columns=[{'id': 'Name', 'label': 'Name', 'field': 'Name', 'align': 'left'}],
  253. rows=[{'Name': f'Person {i}'} for i in range(100)],
  254. pagination=3,
  255. on_pagination_change=lambda e: ui.notify(e.value),
  256. )
  257. @doc.demo('Computed props', '''
  258. You can access the computed props of a table within async callback functions.
  259. ''')
  260. def computed_props():
  261. async def show_filtered_sorted_rows():
  262. ui.notify(await table.get_filtered_sorted_rows())
  263. async def show_computed_rows():
  264. ui.notify(await table.get_computed_rows())
  265. table = ui.table(
  266. columns=[
  267. {'name': 'name', 'label': 'Name', 'field': 'name', 'align': 'left', 'sortable': True},
  268. {'name': 'age', 'label': 'Age', 'field': 'age', 'align': 'left', 'sortable': True}
  269. ],
  270. rows=[
  271. {'name': 'Noah', 'age': 33},
  272. {'name': 'Emma', 'age': 21},
  273. {'name': 'Rose', 'age': 88},
  274. {'name': 'James', 'age': 59},
  275. {'name': 'Olivia', 'age': 62},
  276. {'name': 'Liam', 'age': 18},
  277. ],
  278. row_key='name',
  279. pagination=3,
  280. )
  281. ui.input('Search by name/age').bind_value(table, 'filter')
  282. ui.button('Show filtered/sorted rows', on_click=show_filtered_sorted_rows)
  283. ui.button('Show computed rows', on_click=show_computed_rows)
  284. @doc.demo('Computed fields', '''
  285. You can use functions to compute the value of a column.
  286. The function receives the row as an argument.
  287. See the [Quasar documentation](https://quasar.dev/vue-components/table#defining-the-columns) for more information.
  288. ''')
  289. def computed_fields():
  290. columns = [
  291. {'name': 'name', 'label': 'Name', 'field': 'name', 'align': 'left'},
  292. {'name': 'length', 'label': 'Length', ':field': 'row => row.name.length'},
  293. ]
  294. rows = [
  295. {'name': 'Alice'},
  296. {'name': 'Bob'},
  297. {'name': 'Christopher'},
  298. ]
  299. ui.table(columns=columns, rows=rows, row_key='name')
  300. @doc.demo('Conditional formatting', '''
  301. You can use scoped slots to conditionally format the content of a cell.
  302. See the [Quasar documentation](https://quasar.dev/vue-components/table#example--body-cell-slot)
  303. for more information about body-cell slots.
  304. In this demo we use a `q-badge` to display the age in red if the person is under 21 years old.
  305. We use the `body-cell-age` slot to insert the `q-badge` into the `age` column.
  306. The ":color" attribute of the `q-badge` is set to "red" if the age is under 21, otherwise it is set to "green".
  307. The colon in front of the "color" attribute indicates that the value is a JavaScript expression.
  308. ''')
  309. def conditional_formatting():
  310. columns = [
  311. {'name': 'name', 'label': 'Name', 'field': 'name'},
  312. {'name': 'age', 'label': 'Age', 'field': 'age'},
  313. ]
  314. rows = [
  315. {'name': 'Alice', 'age': 18},
  316. {'name': 'Bob', 'age': 21},
  317. {'name': 'Carol', 'age': 42},
  318. ]
  319. table = ui.table(columns=columns, rows=rows, row_key='name')
  320. table.add_slot('body-cell-age', '''
  321. <q-td key="age" :props="props">
  322. <q-badge :color="props.value < 21 ? 'red' : 'green'">
  323. {{ props.value }}
  324. </q-badge>
  325. </q-td>
  326. ''')
  327. @doc.demo('Table cells with links', '''
  328. Here is a demo of how to insert links into table cells.
  329. We use the `body-cell-link` slot to insert an `<a>` tag into the `link` column.
  330. ''')
  331. def table_cells_with_links():
  332. columns = [
  333. {'name': 'name', 'label': 'Name', 'field': 'name', 'align': 'left'},
  334. {'name': 'link', 'label': 'Link', 'field': 'link', 'align': 'left'},
  335. ]
  336. rows = [
  337. {'name': 'Google', 'link': 'https://google.com'},
  338. {'name': 'Facebook', 'link': 'https://facebook.com'},
  339. {'name': 'Twitter', 'link': 'https://twitter.com'},
  340. ]
  341. table = ui.table(columns=columns, rows=rows, row_key='name')
  342. table.add_slot('body-cell-link', '''
  343. <q-td :props="props">
  344. <a :href="props.value">{{ props.value }}</a>
  345. </q-td>
  346. ''')
  347. @doc.demo('Table with masonry-like grid', '''
  348. You can use the `grid` prop to display the table as a masonry-like grid.
  349. See the [Quasar documentation](https://quasar.dev/vue-components/table#grid-style) for more information.
  350. ''')
  351. def table_with_masonry_like_grid():
  352. columns = [
  353. {'name': 'name', 'label': 'Name', 'field': 'name'},
  354. {'name': 'age', 'label': 'Age', 'field': 'age'},
  355. ]
  356. rows = [
  357. {'name': 'Alice', 'age': 18},
  358. {'name': 'Bob', 'age': 21},
  359. {'name': 'Carol', 'age': 42},
  360. ]
  361. table = ui.table(columns=columns, rows=rows, row_key='name').props('grid')
  362. table.add_slot('item', r'''
  363. <q-card flat bordered :props="props" class="m-1">
  364. <q-card-section class="text-center">
  365. <strong>{{ props.row.name }}</strong>
  366. </q-card-section>
  367. <q-separator />
  368. <q-card-section class="text-center">
  369. <div>{{ props.row.age }} years</div>
  370. </q-card-section>
  371. </q-card>
  372. ''')
  373. doc.reference(ui.table)