Custom script events let you hook into the list webpart lifecycle and react to user actions.
All examples below assume you have access to the global tisa object (List TiSa API).
type onInitComplete = () => Promise<void>;
async function onInitComplete() {
// The list TISA API is fully initialized at this point.
// Use it for early setup, e.g. logging or preparing state.
tisa.log.info("List webpart initialized", { showToast: true });
// Example: check user permissions and store for later use
const membership = await tisa.user.isUserInSPGroup("Approvers");
if (membership.result) {
tisa.log.debug("Current user is an Approver");
}
}
This event runs after the TISA API is initialized and before action buttons are rendered. Use it for async setup, permission checks, or any one-time initialization logic.
type onSelectItem = (selectedItemIds: number[]) => void;
function onSelectItem(selectedItemIds) {
// Example: log the current selection
tisa.log.info(`Selected items: ${selectedItemIds.join(", ")}`);
// Example: get full item data for each selected item
const selectedData = tisa.list.selection.selectedItemsData;
console.log("Selected items data:", selectedData);
// Example: conditionally enable/disable custom actions based on selection
if (selectedItemIds.length === 0) {
tisa.log.debug("No items selected");
}
}
This event fires every time the list selection changes (items are selected or deselected). The selectedItemIds parameter contains an array of currently selected item IDs. Use it to react to selection changes, update external UI, or coordinate with action button visibility/enabled logic.
Note:
onSelectItemis a synchronous event. For async operations triggered by selection changes, start your async work inside the handler but do not return a promise.
The tisa.list object exposes operations on the list data itself.
await tisa.list.reload();
Reloads list items by fetching incremental changes from SharePoint and clears the current selection.
Use it after performing bulk operations (e.g. approving items) instead of location.reload() — it refreshes only the list data without a full page reload.
async function btnApproveCommand() {
await tisa.workflow.start("ApprovalWorkflow");
await tisa.list.reload();
}
Action buttons can reference three types of custom script functions via their JSON configuration:
CommandFunction, EnabledFunction, and VisibleFunction.
All three are looked up by name in the custom script's function namespace.
Called (async) when the user clicks the button.
type CommandFunction = () => Promise<void>;
async function btnApproveCommand() {
const selected = tisa.list.selection.selectedItems;
if (selected.length === 0) {
tisa.log.warn("No items selected.", { showToast: true });
return;
}
await tisa.utils.runWithLoader(async () => {
for (const id of selected) {
await tisa.utils.httpRequest({
url: `${tisa.context.pageContext.web.absoluteUrl}/_api/web/lists/...`,
method: "POST",
body: { itemId: id, action: "Approve" }
});
}
tisa.log.info("Items approved.", { showToast: true });
});
}
A synchronous function that returns boolean. It is re-evaluated whenever the list selection changes.
If EnabledFunction is not set, the button is always enabled.
type EnabledFunction = () => boolean;
function btnApproveEnabled() {
return tisa.list.selection.selectedItems.length > 0;
}
A synchronous function that returns boolean. It is re-evaluated whenever the list selection changes.
If VisibleFunction is not set, the button is always visible.
type VisibleFunction = () => boolean;
// hide the button when more than one item is selected
function btnDetailVisible() {
return tisa.list.selection.selectedItems.length === 1;
}
Below is a complete example showing the JSON configuration together with the matching custom script.
{
"ListUrl": "{SiteUrl}/Lists/Invoices",
"ActionButtons": [
{
"Title": "Action.Approve",
"ToolTipDescription": "Action.Approve.Tooltip",
"ID": "Approve",
"CommandFunction": "btnApproveCommand",
"EnabledFunction": "btnApproveEnabled",
"Icon": { "Icon": "regular/check" }
},
{
"Title": "Action.Detail",
"ID": "Detail",
"CommandFunction": "btnDetailCommand",
"EnabledFunction": "btnDetailEnabled",
"VisibleFunction": "btnDetailVisible",
"Icon": { "Icon": "regular/magnifyingGlass" }
},
{
"Title": "Action.Refresh",
"ID": "Refresh",
"CommandFunction": "btnRefreshCommand",
"Icon": { "Icon": "regular/arrowsRotate" }
}
],
"Resources": [
{
"LCID": "1029",
"Action": {
"Approve": "Schválit",
"Approve.Tooltip": "Schválit vybrané položky",
"Detail": "Detail",
"Refresh": "Obnovit"
}
},
{
"LCID": "1033",
"Action": {
"Approve": "Approve",
"Approve.Tooltip": "Approve selected items",
"Detail": "Detail",
"Refresh": "Refresh"
}
}
]
}
// --- state ---
let isApprover = false;
// --- lifecycle ---
async function onInitComplete() {
const membership = await tisa.user.isUserInSPGroup("Approvers");
isApprover = membership.result;
tisa.log.debug("Init complete, isApprover=" + isApprover);
}
function onSelectItem(selectedItemIds) {
tisa.log.debug("Selection: " + selectedItemIds.join(", "));
}
// --- Approve button ---
function btnApproveEnabled() {
return isApprover && tisa.list.selection.selectedItems.length > 0;
}
async function btnApproveCommand() {
await tisa.workflow.start("ApprovalWorkflow");
tisa.list.selection.deselectAll();
}
// --- Detail button ---
function btnDetailEnabled() {
return tisa.list.selection.selectedItems.length === 1;
}
function btnDetailVisible() {
return tisa.list.selection.selectedItems.length <= 1;
}
async function btnDetailCommand() {
const [id] = tisa.list.selection.selectedItems;
const data = tisa.list.selection.selectedItemsData[0];
tisa.utils.addDialog({
title: tisa.utils.translation("Action.Detail"),
body: "Item #" + id + " – " + (data?.Title ?? "N/A")
});
}
// --- Refresh button ---
async function btnRefreshCommand() {
await tisa.list.reload();
}
Tip:
EnabledFunctionandVisibleFunctionare re-evaluated each time the selection changes, so you can combine permission flags (set inonInitComplete) with selection state to control button availability.