I couldn't get retool's reorderable list hooked up in a way that I could remove elements using onClick. So I created my own reorderable list custom component using Atlassian's react dnd library.
Here is the code in case its helpful to anyone else here!
<style>
body {
margin: 0;
}
</style>
<script src="https://cdn.tryretool.com/js/react.production.min.js" crossorigin></script>
<script src="https://unpkg.com/react-beautiful-dnd@5.0.0/dist/react-beautiful-dnd.js" crossorigin></script>
<script src="https://cdn.tryretool.com/js/react-dom.production.min.js" crossorigin></script>
<script src="https://unpkg.com/@material-ui/core@3.9.3/umd/material-ui.production.min.js"></script>
<div id="react"></div>
<script type="text/babel">
const { Button } = window["material-ui"];
const {DragDropContext, Draggable, Droppable } = window.ReactBeautifulDnd;
const MyCustomComponent = ({ triggerQuery, model, modelUpdate }) =>
{
// a little function to help us with reordering the result
const reorder = (list, startIndex, endIndex) => {
const result = Array.from(list);
const = result.splice(startIndex, 1);
result.splice(endIndex, 0, removed);
return result;
};
const gGrid = 2;
const getItemStyle = (draggableStyle, isDragging) => {
const returnStyle = {
// some basic styles to make the items look a bit nicer
display: "flex",
alignItems: "center",
justifyContent: "space-between",
userSelect: 'none',
padding: gGrid * 2,
margin: `0 0 ${gGrid}px 0`,
color: "white",
fontFamily: "sans-serif",
fontSize: "small",
// change background colour if dragging
background: isDragging ? '#CE316C' : '#E07BA1',
};
return Object.assign(returnStyle, draggableStyle);
}
const getListStyle = (isDraggingOver) => ({
background: isDraggingOver ? '#3c92dc' : '#555F7D',
padding: gGrid,
width: "100%"
});
const updateListState = (newState) => {
console.log("DnD Component:" + JSON.stringify(newState));
modelUpdate({"state": newState, "new_state": newState});
}
const onDragEnd = (result) => {
// dropped outside the list
if(!result.destination) {
return;
}
const newState = reorder(
model.state,
result.source.index,
result.destination.index
);
updateListState(newState);
}
const onRemoveItem = (event) => {
if(event.target)
{
const removeID = event.currentTarget.getAttribute("refid");
const newState = model.state.filter((row) => {return (row.slug != removeID); });
updateListState(newState);
}
}
return (
<DragDropContext onDragEnd={onDragEnd}>
<Droppable droppableId="droppable">
{(provided, snapshot) => (
<div
ref={provided.innerRef}
style={getListStyle(snapshot.isDraggingOver)}
{...provided.droppableProps}
>
{model.state.map((item,index) => (
<Draggable
key={item.slug}
draggableId={item.slug}
index={index}
>
{(provided, snapshot) => (
<div>
<div
ref={provided.innerRef}
{...provided.dragHandleProps}
{...provided.draggableProps}
style={getItemStyle(
provided.draggableProps.style,
snapshot.isDragging
)}
>
<div>{item.title}</div>
<Button size="small" color="primary" variant="contained" refid={item.slug} onClick={onRemoveItem}>Remove</Button>
</div>
{provided.placeholder}
</div>
)}
</Draggable>
))}
{provided.placeholder}
</div>
)}
</Droppable>
</DragDropContext>
);
}
const ConnectedComponent = Retool.connectReactComponent(MyCustomComponent);
ReactDOM.render(<ConnectedComponent />, document.getElementById("react"));
</script>
To use it create a custom component, copy and paste the code above into it and try the component out with this test data:
{"state": [{ "slug": "1", "title": "first item"}, {"slug": "2", "title": "second item"}], }
The sorted list is published to model.new_state