table_documentation.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. from nicegui import ui
  2. from ...model import UiElementDocumentation
  3. class TableDocumentation(UiElementDocumentation, element=ui.table):
  4. def main_demo(self) -> 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. def more(self) -> None:
  16. @self.demo('Table with expandable rows', '''
  17. Scoped slots can be used to insert buttons that toggle the expand state of a table row.
  18. See the [Quasar documentation](https://quasar.dev/vue-components/table#expanding-rows) for more information.
  19. ''')
  20. def table_with_expandable_rows():
  21. columns = [
  22. {'name': 'name', 'label': 'Name', 'field': 'name'},
  23. {'name': 'age', 'label': 'Age', 'field': 'age'},
  24. ]
  25. rows = [
  26. {'name': 'Alice', 'age': 18},
  27. {'name': 'Bob', 'age': 21},
  28. {'name': 'Carol'},
  29. ]
  30. table = ui.table(columns=columns, rows=rows, row_key='name').classes('w-72')
  31. table.add_slot('header', r'''
  32. <q-tr :props="props">
  33. <q-th auto-width />
  34. <q-th v-for="col in props.cols" :key="col.name" :props="props">
  35. {{ col.label }}
  36. </q-th>
  37. </q-tr>
  38. ''')
  39. table.add_slot('body', r'''
  40. <q-tr :props="props">
  41. <q-td auto-width>
  42. <q-btn size="sm" color="accent" round dense
  43. @click="props.expand = !props.expand"
  44. :icon="props.expand ? 'remove' : 'add'" />
  45. </q-td>
  46. <q-td v-for="col in props.cols" :key="col.name" :props="props">
  47. {{ col.value }}
  48. </q-td>
  49. </q-tr>
  50. <q-tr v-show="props.expand" :props="props">
  51. <q-td colspan="100%">
  52. <div class="text-left">This is {{ props.row.name }}.</div>
  53. </q-td>
  54. </q-tr>
  55. ''')
  56. @self.demo('Show and hide columns', '''
  57. Here is an example of how to show and hide columns in a table.
  58. ''')
  59. def show_and_hide_columns():
  60. from typing import Dict
  61. columns = [
  62. {'name': 'name', 'label': 'Name', 'field': 'name', 'required': True, 'align': 'left'},
  63. {'name': 'age', 'label': 'Age', 'field': 'age', 'sortable': True},
  64. ]
  65. rows = [
  66. {'name': 'Alice', 'age': 18},
  67. {'name': 'Bob', 'age': 21},
  68. {'name': 'Carol'},
  69. ]
  70. table = ui.table(columns=columns, rows=rows, row_key='name')
  71. def toggle(column: Dict, visible: bool) -> None:
  72. column['classes'] = '' if visible else 'hidden'
  73. column['headerClasses'] = '' if visible else 'hidden'
  74. table.update()
  75. with ui.button(icon='menu'):
  76. with ui.menu(), ui.column().classes('gap-0 p-2'):
  77. for column in columns:
  78. ui.switch(column['label'], value=True, on_change=lambda e,
  79. column=column: toggle(column, e.value))
  80. @self.demo('Table with drop down selection', '''
  81. Here is an example of how to use a drop down selection in a table.
  82. After emitting a `rename` event from the scoped slot, the `rename` function updates the table rows.
  83. ''')
  84. def table_with_drop_down_selection():
  85. from nicegui import events
  86. columns = [
  87. {'name': 'name', 'label': 'Name', 'field': 'name'},
  88. {'name': 'age', 'label': 'Age', 'field': 'age'},
  89. ]
  90. rows = [
  91. {'id': 0, 'name': 'Alice', 'age': 18},
  92. {'id': 1, 'name': 'Bob', 'age': 21},
  93. {'id': 2, 'name': 'Carol'},
  94. ]
  95. name_options = ['Alice', 'Bob', 'Carol']
  96. def rename(e: events.GenericEventArguments) -> None:
  97. for row in rows:
  98. if row['id'] == e.args['id']:
  99. row['name'] = e.args['name']
  100. ui.notify(f'Table.rows is now: {table.rows}')
  101. table = ui.table(columns=columns, rows=rows, row_key='name').classes('w-full')
  102. table.add_slot('body', r'''
  103. <q-tr :props="props">
  104. <q-td key="name" :props="props">
  105. <q-select
  106. v-model="props.row.name"
  107. :options="''' + str(name_options) + r'''"
  108. @update:model-value="() => $parent.$emit('rename', props.row)"
  109. />
  110. </q-td>
  111. <q-td key="age" :props="props">
  112. {{ props.row.age }}
  113. </q-td>
  114. </q-tr>
  115. ''')
  116. table.on('rename', rename)
  117. @self.demo('Table from Pandas DataFrame', '''
  118. You can create a table from a Pandas DataFrame using the `from_pandas` method.
  119. This method takes a Pandas DataFrame as input and returns a table.
  120. ''')
  121. def table_from_pandas_demo():
  122. import pandas as pd
  123. df = pd.DataFrame(data={'col1': [1, 2], 'col2': [3, 4]})
  124. ui.table.from_pandas(df).classes('max-h-40')
  125. @self.demo('Adding rows', '''
  126. It's simple to add new rows with the `add_rows(dict)` method.
  127. ''')
  128. def adding_rows():
  129. import os
  130. import random
  131. def add():
  132. item = os.urandom(10 // 2).hex()
  133. table.add_rows({'id': item, 'count': random.randint(0, 100)})
  134. ui.button('add', on_click=add)
  135. columns = [
  136. {'name': 'id', 'label': 'ID', 'field': 'id'},
  137. {'name': 'count', 'label': 'Count', 'field': 'count'},
  138. ]
  139. table = ui.table(columns=columns, rows=[], row_key='id').classes('w-full')
  140. @self.demo('Custom sorting and formatting', '''
  141. You can define dynamic column attributes using a `:` prefix.
  142. This way you can define custom sorting and formatting functions.
  143. The following example allows sorting the `name` column by length.
  144. The `age` column is formatted to show the age in years.
  145. ''')
  146. def custom_formatting():
  147. columns = [
  148. {
  149. 'name': 'name',
  150. 'label': 'Name',
  151. 'field': 'name',
  152. 'sortable': True,
  153. ':sort': '(a, b, rowA, rowB) => b.length - a.length',
  154. },
  155. {
  156. 'name': 'age',
  157. 'label': 'Age',
  158. 'field': 'age',
  159. ':format': 'value => value + " years"',
  160. },
  161. ]
  162. rows = [
  163. {'name': 'Alice', 'age': 18},
  164. {'name': 'Bob', 'age': 21},
  165. {'name': 'Carl', 'age': 42},
  166. ]
  167. ui.table(columns=columns, rows=rows, row_key='name')
  168. @self.demo('Toggle fullscreen', '''
  169. You can toggle the fullscreen mode of a table using the `toggle_fullscreen()` method.
  170. ''')
  171. def toggle_fullscreen():
  172. table = ui.table(
  173. columns=[{'name': 'name', 'label': 'Name', 'field': 'name'}],
  174. rows=[{'name': 'Alice'}, {'name': 'Bob'}, {'name': 'Carol'}],
  175. ).classes('w-full')
  176. with table.add_slot('top-left'):
  177. def toggle() -> None:
  178. table.toggle_fullscreen()
  179. button.props('icon=fullscreen_exit' if table.is_fullscreen else 'icon=fullscreen')
  180. button = ui.button('Toggle fullscreen', icon='fullscreen', on_click=toggle).props('flat')
  181. @self.demo('Pagination', '''
  182. You can provide either a single integer or a dictionary to define pagination.
  183. The dictionary can contain the following keys:
  184. - `rowsPerPage`: The number of rows per page.
  185. - `sortBy`: The column name to sort by.
  186. - `descending`: Whether to sort in descending order.
  187. - `page`: The current page (1-based).
  188. ''')
  189. def pagination() -> None:
  190. columns = [
  191. {'name': 'name', 'label': 'Name', 'field': 'name', 'required': True, 'align': 'left'},
  192. {'name': 'age', 'label': 'Age', 'field': 'age', 'sortable': True},
  193. ]
  194. rows = [
  195. {'name': 'Elsa', 'age': 18},
  196. {'name': 'Oaken', 'age': 46},
  197. {'name': 'Hans', 'age': 20},
  198. {'name': 'Sven'},
  199. {'name': 'Olaf', 'age': 4},
  200. {'name': 'Anna', 'age': 17},
  201. ]
  202. ui.table(columns=columns, rows=rows, pagination=3)
  203. ui.table(columns=columns, rows=rows, pagination={'rowsPerPage': 4, 'sortBy': 'age', 'page': 2})
  204. @self.demo('Computed fields', '''
  205. You can use functions to compute the value of a column.
  206. The function receives the row as an argument.
  207. See the [Quasar documentation](https://quasar.dev/vue-components/table#defining-the-columns) for more information.
  208. ''')
  209. def computed_fields():
  210. columns = [
  211. {'name': 'name', 'label': 'Name', 'field': 'name', 'align': 'left'},
  212. {'name': 'length', 'label': 'Length', ':field': 'row => row.name.length'},
  213. ]
  214. rows = [
  215. {'name': 'Alice'},
  216. {'name': 'Bob'},
  217. {'name': 'Christopher'},
  218. ]
  219. ui.table(columns=columns, rows=rows, row_key='name')
  220. @self.demo('Conditional formatting', '''
  221. You can use scoped slots to conditionally format the content of a cell.
  222. See the [Quasar documentation](https://quasar.dev/vue-components/table#example--body-cell-slot)
  223. for more information about body-cell slots.
  224. In this demo we use a `q-badge` to display the age in red if the person is under 21 years old.
  225. We use the `body-cell-age` slot to insert the `q-badge` into the `age` column.
  226. The ":color" attribute of the `q-badge` is set to "red" if the age is under 21, otherwise it is set to "green".
  227. The colon in front of the "color" attribute indicates that the value is a JavaScript expression.
  228. ''')
  229. def conditional_formatting():
  230. columns = [
  231. {'name': 'name', 'label': 'Name', 'field': 'name'},
  232. {'name': 'age', 'label': 'Age', 'field': 'age'},
  233. ]
  234. rows = [
  235. {'name': 'Alice', 'age': 18},
  236. {'name': 'Bob', 'age': 21},
  237. {'name': 'Carol', 'age': 42},
  238. ]
  239. table = ui.table(columns=columns, rows=rows, row_key='name')
  240. table.add_slot('body-cell-age', '''
  241. <q-td key="age" :props="props">
  242. <q-badge :color="props.value < 21 ? 'red' : 'green'">
  243. {{ props.value }}
  244. </q-badge>
  245. </q-td>
  246. ''')
  247. @self.demo('Table cells with links', '''
  248. Here is a demo of how to insert links into table cells.
  249. We use the `body-cell-link` slot to insert an `<a>` tag into the `link` column.
  250. ''')
  251. def table_cells_with_links():
  252. columns = [
  253. {'name': 'name', 'label': 'Name', 'field': 'name', 'align': 'left'},
  254. {'name': 'link', 'label': 'Link', 'field': 'link', 'align': 'left'},
  255. ]
  256. rows = [
  257. {'name': 'Google', 'link': 'https://google.com'},
  258. {'name': 'Facebook', 'link': 'https://facebook.com'},
  259. {'name': 'Twitter', 'link': 'https://twitter.com'},
  260. ]
  261. table = ui.table(columns=columns, rows=rows, row_key='name')
  262. table.add_slot('body-cell-link', '''
  263. <q-td :props="props">
  264. <a :href="props.value">{{ props.value }}</a>
  265. </q-td>
  266. ''')