2. Act on the list
The table lists authors; now a librarian needs to change the list. Every change is an Arc command, and Components turns each one into a form-with-a-button without you binding a single field. We’ll start with RegisterAuthor.
Add an author
Section titled “Add an author”-
Build the dialog from the command.
CommandDialogtakes the generated command, renders the fields you list plus the OK/Cancel footer, validates, and executes on confirm. The field accessor(command) => command.nameis typed againstRegisterAuthor:src/AddAuthor.tsx import { useState } from 'react';import { Guid } from '@cratis/fundamentals';import { CommandDialog } from '@cratis/components/CommandDialog';import { InputTextField } from '@cratis/components/CommandForm';import { RegisterAuthor } from './Authors/RegisterAuthor'; // generated proxyexport const AddAuthor = () => {const [id] = useState(() => Guid.create());return (<CommandDialog<RegisterAuthor>command={RegisterAuthor}title='Add author'okLabel='Add'initialValues={{ id }}><InputTextField<RegisterAuthor>value={(command) => command.name}title='Name'placeholder='Sample Author'/></CommandDialog>);};RegisterAuthorrequires anidthat the librarian never types, so the dialog creates one and passes it ininitialValues. The command is complete except for the name from the moment the dialog opens. -
Open it from the screen.
useDialogfrom Arc gives you a wrapper element to render and a function to show it. Add a button above the table from chapter 1:src/Authors.tsx import { useDialog } from '@cratis/arc.react/dialogs';import { Button, Page } from '@cratis/components/Common';import { Column, DataTableForObservableQuery } from '@cratis/components/DataTables';import { AllAuthors } from './Authors/Author';import { AddAuthor } from './AddAuthor';export const Authors = () => {const [AddAuthorDialog, showAddAuthor] = useDialog(AddAuthor);return (<Page title='Authors'><Button label='Add author' onClick={() => void showAddAuthor()} /><DataTableForObservableQuery query={AllAuthors} emptyMessage='No authors yet'><Column field='name' header='Name' sortable /></DataTableForObservableQuery><AddAuthorDialog /></Page>);}; -
Try it. Click Add author. The dialog opens with Add disabled, because the required name is still empty. Type a name and Add enables. Confirm, and the dialog shows its busy state while
RegisterAuthorexecutes, then closes.
useDialog mounts AddAuthor only while the dialog is open, so every click creates a fresh id. You didn’t wire the buttons either: CommandDialog closes itself through the dialog context when the command succeeds, and Cancel, the close button, and Escape close it without executing.
The payoff: it updates itself
Section titled “The payoff: it updates itself”Add an author and the new row appears in the table immediately — and you wrote nothing to make that happen. There’s no “reload the list after saving,” because there’s nothing to reload: the command stored the author, the observable AllAuthors query pushed its new result, and the table you built in chapter 1 re-rendered on its own. The write side and the read side meet in the data, and the screen just follows.
Rename and remove are just more commands
Section titled “Rename and remove are just more commands”Editing isn’t a different mechanism — it’s another command. The Arc tutorial doesn’t define rename or remove commands, but if you add a RenameAuthor command with an id and a name, its dialog follows the same shape. It needs to know which author, so pass the selected author’s id and current name as initialValues. This excerpt assumes an author variable holding the selected row:
<CommandDialog<RenameAuthor> command={RenameAuthor} title='Rename author' okLabel='Save' initialValues={{ id: author.id, name: author.name }}> <InputTextField<RenameAuthor> value={(command) => command.name} title='Name' /></CommandDialog>A remove command with nothing but the id is often a confirmation rather than a form; pass initialFocus={DialogInitialFocus.Cancel} (from @cratis/components/Dialogs) so a stray Enter doesn’t confirm it. The table updates itself after every one of these, the same way it did for adding. In the next chapter you’ll get the selected row from DataPage and pass it to a real command from the Arc tutorial, AddBook.
What you built
Section titled “What you built”- An Add author dialog generated from the
RegisterAuthorcommand, opened withuseDialog, with its requiredidininitialValues, - a table that updates live the moment the command lands — no refresh code,
- and the pattern for every other change: model it as a command, open it in a dialog, let the list follow.
These actions hang off a button above the table, but a real list screen lets you select a row and act on it — and often shows that row’s details beside the list. That’s exactly what DataPage is for. Let’s build the list-and-detail screen →