Components
Row actions
What a list row can do, at its end, behind one ⋯: the menu Flux's table demo opens from each row — look at it, edit it, what the page adds, and delete it, asking first. Not one of Flux UI's components: the kit's own, worded from the RaskStrings catalog.
Edit and delete
Edit(url) is where the menu's edit item goes. Remove(delete, heading, question) adds the delete, last and in red, which asks in the layout's Ui.Confirm and deletes only on yes; a row that cannot be deleted passes null and has none. It is the row's last cell itself; its column is Ui.TableColumn.RowMenu.
namespace Rask.Site.Features.UiDocs.Examples;
// The ⋯ opens the row's menu: Edit opens its form, Delete asks in the layout's Ui.Confirm. A supplier with orders cannot be deleted.
public sealed partial class RowActionsExample : Component
{
private static readonly Supplier[] Everyone =
[
new("Aminoff Freight", "Oslo", Orders: 3), new("Bothman & Sons", "Leeds", Orders: 0), new("Geidt Logistics", "Porto", Orders: 0),
];
private List<Supplier> _suppliers = [.. Everyone];
protected override Component? Render() =>
Div.Class("grid gap-3")[
Div[Ui.Button.Key("restore").Sm.OnClick(() => { _suppliers = [.. Everyone]; })["Restore"]],
Ui.Table.Id("ura-suppliers").ContainerClass("min-w-0")[
Ui.TableColumns[
Ui.TableColumn["Supplier"],
Ui.TableColumn.Width(Ui.ColumnWidth.Reference)["City"],
Ui.TableColumn.RowMenu
],
Ui.TableRows[
_suppliers.Select(supplier => Ui.TableRow.Key(supplier.Name)[
Ui.TableCell.Variant(Ui.TableCellVariant.Strong).Cut(supplier.Name),
Ui.TableCell.Cut(supplier.City),
Ui.RowActions.Key(supplier.Name).Edit(Routes.UiFormButtonsPage()).Remove(Removal(supplier), "Delete supplier", $"Delete {supplier.Name}?")
])
]
]
];
// A supplier with orders cannot be deleted: no delete in its menu.
private Action? Removal(Supplier supplier) => supplier.Orders == 0 ? () => _suppliers.Remove(supplier) : null;
private sealed record Supplier(string Name, string City, int Orders);
}View, and what the row adds
A ghost ⋯ opening at the bottom end, as Flux's table demo does, holds View(url), Edit(url) — or OnEdit to edit the row where it stands — what the row puts inside, then the delete, apart and in red, asking first. None is required; a row nothing can be done with has no ⋯. The cell keeps to the table's right edge while the other columns scroll under it; its column is Ui.TableColumn.RowMenu. Inside a keyed row it needs no key of its own: a press that arrives after a row above it went still reaches its own row.
using System.Globalization;
namespace Rask.Site.Features.UiDocs.Examples;
// Everything a row can do behind one ⋯: look at it, edit it, what the page adds, and the delete last, asking first.
// Its column keeps to the table's right edge while the others scroll under it. A supplier with orders cannot be deleted.
public sealed partial class RowActionsMenuExample : Component
{
private static readonly Supplier[] Everyone =
[
new("Aminoff Freight", "Oslo", "NO 912 345 678", Orders: 3), new("Bothman & Sons", "Leeds", "GB 123 4567 89", Orders: 0),
new("Geidt Logistics", "Porto", "PT 501 234 567", Orders: 0),
];
private List<Supplier> _suppliers = [.. Everyone];
private string? _chosen;
protected override Component? Render() =>
Div.Class("grid gap-3")[
Div.Class("flex items-center gap-3")[
Ui.Button.Key("restore").Sm.OnClick(() => { _suppliers = [.. Everyone]; _chosen = null; })["Restore"],
Ui.Text.Id("urm-chosen")[_chosen is null ? "No supplier chosen." : $"Chosen: {_chosen}."]
],
Ui.Table.Id("urm-suppliers").ContainerClass("min-w-0")[
Ui.TableColumns[
Ui.TableColumn["Supplier"],
Ui.TableColumn.Reference["City"],
Ui.TableColumn.Short["VAT number"],
Ui.TableColumn.Number["Orders"],
Ui.TableColumn.RowMenu
],
Ui.TableRows[
_suppliers.Select(supplier => Ui.TableRow.Key(supplier.Name)[
Ui.TableCell.Variant(Ui.TableCellVariant.Strong).Cut(supplier.Name),
Ui.TableCell.Cut(supplier.City),
Ui.TableCell.Cut(supplier.Vat),
Ui.TableCell.End[supplier.Orders.ToString(CultureInfo.InvariantCulture)],
Ui.RowActions.Key(supplier.Name)
.View(Routes.UiTablePage())
.Edit(Routes.UiFormButtonsPage())
.Remove(Removal(supplier), "Delete supplier", $"Delete {supplier.Name}?")[
Ui.MenuItem.Icon(Ui.IconName.Check).OnClick(() => { _chosen = supplier.Name; })["Choose"]
]
])
]
]
];
// A supplier with orders cannot be deleted: no delete in its menu.
private Action? Removal(Supplier supplier) => supplier.Orders == 0 ? () => _suppliers.Remove(supplier) : null;
private sealed record Supplier(string Name, string City, string Vat, int Orders);
}Reference
Ui.RowActions
A list row's last cell: all it can do behind one ghost ⋯ opening a dropdown at the bottom end, as Flux's table demo does, in a py-0 cell held at the table's right edge. Its column is Ui.TableColumn.RowMenu.
Step | Takes | What it does |
|---|---|---|
.View(…) | a route: Routes.SupplierPage(id) | Where the row opens to be looked at: the menu's first item, an eye. |
.Edit(…) | a route: Routes.EditSupplierPage(id) | Where the menu's edit item opens the row to be edited. Unset, there is none. |
.OnEdit(…) | a handler, with no argument | Edits the row where it stands: the menu's edit item is a button. Wins over Edit. |
.Remove(…) | the delete, then the question's heading and the question (the catalog's when null) | The menu's last item, apart and in red, that asks first, in the layout's Ui.Confirm, and runs the delete on yes. Null draws none. |
.OnRemove(…) | a handler, with no argument | The delete alone, asking the catalog's question: "Are you sure you want to delete it?" |
.RemoveHeading(…) | string | The title over the delete's question, and the delete item's words. "Delete" when unset. |
.RemoveQuestion(…) | string | The question the delete asks first. |