Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: created section for extension list-of-values #328

Merged
merged 12 commits into from
Dec 6, 2024
159 changes: 159 additions & 0 deletions docs/userman/gui/extension/dynamic_element/list_of_value_props.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
The previous section on [Tabular properties](tabular_data_props.md) explains creating dynamic elements for tabular data values.
namnguyen20999 marked this conversation as resolved.
Show resolved Hide resolved
For collections like lists, a more complex setup is needed to support dynamically updating arrays. In Taipy GUI, lists
namnguyen20999 marked this conversation as resolved.
Show resolved Hide resolved
can bind to Python variables or expressions, instantly reflecting changes in the UI. Custom elements handling lists must
declare their properties, similar to tabular properties, using the PropertyType class to define array formats. This allows
namnguyen20999 marked this conversation as resolved.
Show resolved Hide resolved
multidimensional data binding, so any changes to the list refresh the UI display.
namnguyen20999 marked this conversation as resolved.
Show resolved Hide resolved

# Using list of values

In this section, we will expand the dynamic element library by adding a new dynamic custom element.
namnguyen20999 marked this conversation as resolved.
Show resolved Hide resolved

This dynamic element will accept a property containing a list of values and display it within a list. When a Python
variable is bound to this property, updates to the variable will immediately reflect in the list content shown on the
page, ensuring real-time synchronization.

## Declaring a dynamic element {data-source="gui:doc/extension/example_library/example_library.py#L45"}

Starting from the code mentioned above, here is how you would declare this new element:
```py title="example_library.py"
namnguyen20999 marked this conversation as resolved.
Show resolved Hide resolved
from taipy.gui.extension import Element, ElementLibrary, ElementProperty, PropertyType

class ExampleLibrary(ElementLibrary):
def __init__(self) -> None:
# Initialize the set of visual elements for this extension library
self.elements = {
"visual_label_list": Element(
"lov",
{
"lov": ElementProperty(PropertyType.lov),
"sort": ElementProperty(PropertyType.string),
},
# The name of the React component (VisualLabelList) that implements this custom
# element, exported as LabeledItemList in front-end/src/index.ts
react_component="VisualLabelList",
)
}
```
The declaration of this dynamic element is very similar to what we created in the
[Tabular properties](tabular_data_props.md). The detailed explanation of the code is as follows:
namnguyen20999 marked this conversation as resolved.
Show resolved Hide resolved

- The *visual_label_list* element includes two properties: *lov* and *sort*.
- The *lov* property has the type *PropertyType.lov*, meaning it holds a list of value and is dynamic.
namnguyen20999 marked this conversation as resolved.
Show resolved Hide resolved
- The *sort* property has the type *PropertyType.string*, meaning it holds a string value. Because this property is
namnguyen20999 marked this conversation as resolved.
Show resolved Hide resolved
static, it would nevertheless not reflect changes in the bound variable values.
namnguyen20999 marked this conversation as resolved.
Show resolved Hide resolved
- The *get_name()* method in the *ExampleLibrary* class returns the name of the library as a string. This name is used
namnguyen20999 marked this conversation as resolved.
Show resolved Hide resolved
to identify the library within the Taipy GUI framework.
- The *get_elements()* method in the *ExampleLibrary* class returns a dictionary of all elements that are part of this
library. Each element is defined with its properties and associated React component.

## Creating the React component {data-source="gui:doc/extension/example_library/front-end/src/VisualLabelList.tsx"}

The React component for the *visual_label_list* element is defined as follows:
```tsx title="VisualLabelList.tsx" linenums="1"
import React, { useMemo } from "react";
import { LoV, useLovListMemo } from "taipy-gui";

interface VisualLabelListProps {
lov?: LoV;
defaultLov?: string;
sort?: "asc" | "desc";
}

const styles = {
listItem: {
display: "flex",
alignItems: "center",
},
image: {
marginRight: "8px",
width: "1em",
height: "1em",
},
};

const VisualLabelList: React.FC<VisualLabelListProps> = ({ lov, defaultLov = "", sort }) => {
const lovList = useLovListMemo(lov, defaultLov);

const sortedLovList = useMemo(() => {
if (sort) {
return lovList.slice().sort((a, b) => {
return sort === "asc" ? a.id.localeCompare(b.id) : b.id.localeCompare(a.id);
});
}
return lovList;
}, [lovList, sort]);

return (
<div>
<ul>
{sortedLovList.map((item, index) => (
<li key={index} style={styles.listItem}>
{typeof item.item === "string" ? null : (
<img src={item.item.path} alt={item.item.text} style={styles.image} />
)}
{item.id}
</li>
))}
</ul>
</div>
);
};

export default VisualLabelList;
```

The detailed explanation of the code is as follows:

- The *lov* property, defined as *PropertyType.lov*, expects a value of type
namnguyen20999 marked this conversation as resolved.
Show resolved Hide resolved
[*LoV*](../../../../refmans/reference_guiext/type-aliases/LoV.md).
- Using Taipy GUI’s [*useLovListMemo*](../../../../refmans/reference_guiext/functions/useLovListMemo.md) hook, we
namnguyen20999 marked this conversation as resolved.
Show resolved Hide resolved
create a memoized list of values based on this *lov* property, efficiently managing the component’s list of values.
- To enhance this list, we can apply sorting using the *sort* property, which accepts either “asc” for ascending or
“desc” for descending order. Since *sort* remains static, a default value is unnecessary: when set to “asc” or
“desc,” the list is sorted accordingly, while an unset *sort* property displays values in their original order.

## Exporting the React component {data-source="gui:doc/extension/example_library/front-end/src/index.ts"}

When the component is entirely defined, it must be exported by the JavaScript library.
namnguyen20999 marked this conversation as resolved.
Show resolved Hide resolved
This is done by adding the export directive in the file *<project dir>/<package dir>front-end/src/index.ts*.

```js title="index.ts"
import VisualLabelList from "./VisualLabelList";

export { VisualLabelList };
```

## Using the element {data-source="gui:doc/extension/visual_label_list.py"}

To use the *visual_label_list* element in a Python script, you can follow the example below:
```py title="List of items"
languages = [
["Python", Icon("images/python.png", "Python logo")],
["JavaScript", Icon("images/javascript.png", "JavaScript logo")],
["TypeScript", Icon("images/typescript.png", "TypeScript logo")],
["Java", Icon("images/java.png", "Java logo")],
["C++", Icon("images/cpp.png", "C++ logo")],
]

page = """
<|{languages}|example.visual_label_list|sort=asc|>
"""
```

In this example, the *languages* list contains a [*list of value*](../../binding.md#list-of-values),
each with a name and an icon. The *page* variable contains a string that uses the *visual_label_list* element to display
the list of languages in ascending order. The *sort* property is set to “asc” to sort the list alphabetically by
language name. When the page is rendered, the list will display the languages in the specified order.

By following these steps, you can create a dynamic element that displays a list of values and updates in real time as
the underlying data changes. This approach allows you to build custom elements that can manage and display collections
of data, providing a more interactive and responsive user interface.

When you run this application, the page displays the element like this:

<figure>
<img src="../visual_label_list-d.png" class="visible-dark"/>
<img src="../visual_label_list-l.png" class="visible-light"/>
<figcaption>Visual labeled list</figcaption>
</figure>

Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ The detailed explanation of the code is as follows:

The React component for the *game_table* element is defined as follows:

```jsx title="GameTable.tsx" linenums="1"
```tsx title="GameTable.tsx" linenums="1"
import React, { useEffect, useMemo, useState } from "react";
import {
createRequestDataUpdateAction,
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
211 changes: 0 additions & 211 deletions docs/userman/gui/extension/extension_data.md

This file was deleted.

10 changes: 0 additions & 10 deletions docs/userman/gui/extension/extension_list_of_values.md

This file was deleted.

Loading
Loading