class SortableList
A reactive HTML component that displays a sortable and deletable list of items with drag-and-drop functionality using SortableJS library.
/tf/active/vicechatdev/resources/py2html.py
294 - 376
moderate
Purpose
SortableList provides an interactive UI component for managing a list of string items where users can reorder items by dragging them and delete items by clicking a trash icon. It extends Panel's ReactiveHTML to create a custom widget with bidirectional data binding between Python and JavaScript. The component is useful for building interactive dashboards, form builders, or any application requiring user-managed ordered lists.
Source Code
class SortableList(ReactiveHTML):
"""
A list where each item can be sorted or deleted by dragging and dropping it
Parameters
----------
rows : list of str
The items to list
label : str
The label above the list
"""
rows = param.List(default=[])
label = param.String(default="My list")
list_trigger = param.Integer(default=0)
_template = """
<label for="simpleList" style="font-size:16px; color: #5564be;">{{ label }}</label>
<div id="simpleList" class="list-group"></div>
"""
_scripts = {
'render': """
var html = ""
data.rows.forEach(setRows);
function setRows(value, index, array) {
html += `<div class="list-group-item" style="font-size:14px;"><i class="fas fa-arrows-alt handle" style="margin-right: 10px;"></i>${value}<span style="float:right;"><i id="delete" target="${value}" class="fa fa-trash"></i></span></div>`
}
simpleList.innerHTML = html
""",
'after_layout': """
state.sortable = Sortable.create(simpleList, {
removeOnSpill: true,
handle: '.handle',
animation: 150,
onEnd: function(evt) {
var target = evt.originalEvent.target;
if (simpleList !== target && !simpleList.contains(target)) {
list = data.rows
var index = list.indexOf(target.textContent)
list.splice(index, 1)
data.rows = list
}
var element = data.rows[evt.oldIndex];
list = data.rows
list.splice(evt.oldIndex, 1);
list.splice(evt.newIndex, 0, element);
data.rows = list
}
});
self.set_onclick()
""",
"rows": """
console.log("running rows")
state.sortable.destroy()
self.render()
self.after_layout()
""",
"set_onclick":"""
console.log("setting on click")
const list_of_targets = document.querySelectorAll("#delete")
list_of_targets.forEach(setWatcher)
function setWatcher(el) {
el.onclick = self.dropRow
};
""",
"dropRow":"""
var target = event.target.getAttribute('target')
list = data.rows
var index = list.indexOf(target)
list.splice(index, 1)
data.rows = list
self.rows()
data.list_trigger+=1
""",
}
__javascript__=[
"https://raw.githack.com/SortableJS/Sortable/master/Sortable.js"
]
@param.output(param.List)
def list_out(self):
return self.rows
Parameters
| Name | Type | Default | Kind |
|---|---|---|---|
bases |
ReactiveHTML | - |
Parameter Details
rows: A list of strings representing the items to display in the sortable list. Each string becomes a draggable list item. Default is an empty list. This parameter is reactive and updates trigger re-rendering of the list.
label: A string that appears as the header/title above the list. Default is 'My list'. Displayed in a styled label element with blue color (#5564be) and 16px font size.
list_trigger: An integer counter used internally to track list modifications (deletions). Increments when items are deleted. Default is 0. This is primarily for triggering reactive updates and should not typically be set by users.
Return Value
Instantiation returns a SortableList object that can be added to Panel layouts. The list_out() method returns the current list of items (rows) as a Python list, which can be used to retrieve the user-modified list state.
Class Interface
Methods
list_out() -> list
Purpose: Returns the current list of items in the sortable list
Returns: A list of strings representing the current items in the sortable list after any user modifications (reordering or deletions)
render() -> None
Purpose: JavaScript method that generates the HTML for list items from the rows data
Returns: None - updates the DOM directly by setting innerHTML of the simpleList element
after_layout() -> None
Purpose: JavaScript method that initializes the SortableJS instance after the DOM is ready and sets up event handlers
Returns: None - creates the Sortable instance and attaches it to state.sortable
set_onclick() -> None
Purpose: JavaScript method that attaches click event handlers to all delete buttons in the list
Returns: None - sets onclick handlers for elements with id='delete'
dropRow(event) -> None
Purpose: JavaScript method that handles deletion of a list item when the trash icon is clicked
Parameters:
event: JavaScript event object containing the click event with target information
Returns: None - removes the item from data.rows and triggers re-render
Attributes
| Name | Type | Description | Scope |
|---|---|---|---|
rows |
param.List | List of string items to display in the sortable list. Reactive parameter that triggers re-rendering when modified. | class |
label |
param.String | The label text displayed above the list. Default is 'My list'. | class |
list_trigger |
param.Integer | Counter that increments when items are deleted. Used to trigger reactive updates. Default is 0. | class |
_template |
str | HTML template string defining the structure of the component with label and list container elements. | class |
_scripts |
dict | Dictionary mapping script names to JavaScript code strings that define the component's interactive behavior. | class |
__javascript__ |
list | List of external JavaScript library URLs to load. Contains the SortableJS CDN URL. | class |
Dependencies
parampanelSortableJS
Required Imports
import param
import panel as pn
from panel.reactive import ReactiveHTML
Usage Example
import panel as pn
import param
from panel.reactive import ReactiveHTML
# Define the SortableList class (code provided above)
# Create an instance with initial items
sortable_list = SortableList(
rows=['Item 1', 'Item 2', 'Item 3', 'Item 4'],
label='My Tasks'
)
# Display in a Panel application
pn.extension()
app = pn.Column(sortable_list)
app.servable()
# Access the current list state
current_items = sortable_list.list_out()
print(current_items) # ['Item 1', 'Item 2', 'Item 3', 'Item 4']
# Programmatically update the list
sortable_list.rows = ['New Item 1', 'New Item 2']
# Watch for changes
def on_list_change(event):
print(f'List updated: {event.new}')
sortable_list.param.watch(on_list_change, 'list_trigger')
Best Practices
- Always initialize with a list of strings for the rows parameter; non-string items may not render correctly
- Use the list_trigger parameter to watch for deletion events rather than directly monitoring rows, as it provides a cleaner signal for user-initiated deletions
- Call list_out() method to retrieve the current state of the list after user interactions
- Ensure Panel extension is loaded with pn.extension() before displaying the component
- The component requires a JavaScript environment (browser) to function; it cannot be used in pure Python contexts
- When embedding in larger applications, be aware that the SortableJS library is loaded from a CDN and requires internet connectivity
- The rows parameter is reactive - modifying it programmatically will trigger a re-render of the list
- Avoid rapid programmatic updates to rows as each change triggers a destroy/recreate cycle of the Sortable instance
Tags
Similar Components
AI-powered semantic similarity - components with related functionality:
-
class Carrousel 47.5% similar
-
class Scrollmenu 45.4% similar
-
class Extending_row 44.6% similar
-
class Extending_column 42.9% similar
-
class JSTree_json 41.8% similar