Make Cancel mean that nothing changed
A card window is a container for an interface, not an automatic undo boundary. If its fields are bound directly to the contact record, the user may already have changed business data before clicking Cancel.
For this design, the card edits a temporary proposal. Save validates that proposal and writes it in a controlled transaction. Cancel discards only the proposal. It does not revert unrelated work in the parent window.
Start in a teaching copy with one committed contact: Maya Chen. The first acceptance check is simple: change the proposed name to Maya Patel, click Cancel, and confirm the saved contact is still Maya Chen.
Create a small edit buffer
| Field or state | Type | Purpose |
|---|---|---|
| UI::gName | Global text | Proposed name |
| UI::gOriginalName | Global text | Name read when editing began |
| UI::gContactUUID | Global text | Stable target identity |
| UI::gOriginalRevision | Global number | Application revision read at open |
| UI::gError | Global text | Recoverable feedback |
| Contacts::Revision | Stored number | Incremented by every supported contact writer |
Put only gName in the editable name control. Show the error beside it. Initialize every buffer field on every opening; global fields can retain values for the session. Enforce one editor at a time because these globals are shared by windows in that session.
For multiple simultaneous editors, use an edit-session record keyed by an editor UUID instead of this single buffer. A global field is not automatically a separate value per window.
Open from a clean record context
Before opening, require the parent workflow’s changes to be resolved explicitly. Do not quietly commit or revert them to make the card work. On a simple contact layout, Get(RecordOpenCount) can detect unsaved records in its current found set, including related records; it is not a whole-file transaction audit.
FileMaker controller fragment · initialize the editor
If [ Get ( RecordOpenCount ) > 0 ]
Exit Script [ Text Result: "finish_current_edit_first" ]
End If
# Also enforce the controller's no-active-editor/no-active-transaction rule.
Set Field [ UI::gName ; Contacts::FullName ]
Set Field [ UI::gOriginalName ; Contacts::FullName ]
Set Field [ UI::gContactUUID ; Contacts::ContactUUID ]
Set Field [ UI::gOriginalRevision ; Contacts::Revision ]
Set Field [ UI::gError ; "" ]
# Check each buffer assignment before opening the card.
New Window [ Style: Card ; Name: "Contact edit" ;
Using layout: "Contact edit" (Contacts) ]
# Configure the card's Close option off; use explicit Save/Cancel buttons.The card layout uses Contacts context but its editable control targets the UI global. Inspect its layout triggers: none should write to Contacts simply because the card opens or a buffer field changes. If card creation fails, clear the editor guard and return an error instead of leaving the app stuck.
Save under a lock, after checking for changes
Do not keep the contact locked while someone types. On Save, first validate the proposal, then resolve the saved ContactUUID in the card’s context, lock the target and re-read it. Compare its Revision with the revision captured at open. Every supported writer must increment that revision; otherwise this conflict check is incomplete.
Workflow pseudocode · save a buffered edit
Save:
Copy gName to a local proposal variable.
If trimmed proposal is empty: show error; keep the card open.
Begin a short transaction in the card window.
Find exactly the saved ContactUUID; require one accessible record.
Open Record/Request and immediately check for a lock/error.
Re-read Revision after acquiring the lock.
If Revision differs from gOriginalRevision: revert; show conflict.
Set FullName to the validated proposal.
Set Revision to the current revision + 1.
Check every write; commit only if all succeeded.
If commit failed: keep the proposal and show a recoverable error.
If commit succeeded: clear buffer/guard and close the editor.This is the controller design, not a complete importable script. Configure Open Record/Request, exact find criteria, privilege checks and the transaction error paths in your own file. Do not use an ordinary name search to locate the target.
Keep all writes in the card’s transaction window and leave validation enabled. On a revision conflict, show the current saved value and the proposal. Offer Reload current value with a clear warning that it discards the proposal, or let the user copy the proposal for review. Do not overwrite another person’s change automatically.
Cancel without touching the contact
Cancel clears the buffer and editor state, then closes the card. It does not call Revert Record on the parent window and does not write FullName. Use an explicit Cancel button; route any enabled keyboard or close gesture to the same cancellation policy.
FileMaker script fragment · discard the proposal
# Cancel fragment: run only in this editor's card window.
Set Field [ UI::gName ; "" ]
Set Field [ UI::gOriginalName ; "" ]
Set Field [ UI::gContactUUID ; "" ]
Set Field [ UI::gOriginalRevision ; "" ]
Set Field [ UI::gError ; "" ]
# Clear the active-editor guard after checking the cleanup result.
Close Window [ Current Window ]A failed Save must leave the proposal intact until the person chooses Cancel or another action. Do not run this cleanup unconditionally after a save attempt. On the next opening, initialize from the saved target again, even if the last close was interrupted.
Review the whole editing journey
| Action | Expected result |
|---|---|
| Change name, then Cancel | Original contact unchanged |
| Enter blank name, then Save | Card stays open with feedback |
| Save a valid new name | One committed update; card closes |
| Another user changes the contact after opening | Conflict shown; no silent overwrite |
| Target is locked or inaccessible | Proposal retained; no partial save |
| Open another contact after Cancel | No previous contact’s buffer values |
Also test a repeated Save click and the intended close/keyboard behavior. Verify the stored contact after reopening, not only the text shown on screen. Styling the card with a theme does not implement any of these save or cancellation rules.
References
Primary references checked during preparation. Provider-specific contracts and native behavior still require review for your implementation.