bcquality/microsoft/knowledge/ui/list-page-document-routing-uses-page-management.md
Michael Dieringer 750466c7f3 Add UI knowledge: notification recall Id and Page Management document routing
Two ui articles with compiled good/bad samples:
- notification-recall-needs-known-id: a notification that the code also
  recalls needs a fixed Id (single instance; recall before re-send) or
  per-record tracking through codeunit "Notification Lifecycle Mgt."
  (SendNotification[WithAdditionalContext] / RecallNotificationsForRecord,
  HandleDelayedInsert semantics). Never-recalled notifications are exempt.
- list-page-document-routing-uses-page-management: open documents from a
  mixed-type list with PageManagement.PageRun(Rec) instead of a hand-written
  case "Document Type" / Page.Run; register new tables through
  OnConditionalCardPageIDNotFound. Single-type opens and tables Page
  Management does not route are exempt.

Wired into al-ui-review (entry gate now covers notification send/recall
outside pages, tokens, high-signal mappings) and registered both pairs in
the ui review-fixtures override.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 12:47:57 +02:00

5.3 KiB

bc-version domain keywords technologies countries application-area
all
ui
page-management
pagerun
show-document
document-type
cardpageid
list-page
page-run
getconditionalcardpageid
onconditionalcardpageidnotfound
al
w1
all

Open documents from a mixed-type list through Page Management

Description

Some tables back several document pages, chosen by a type field. Sales Header rows open as Sales Quote, Sales Order, Sales Invoice, Sales Credit Memo, Blanket Sales Order, or Sales Return Order, depending on Document Type. A list over such a table cannot use one CardPageID. Codeunit 700 "Page Management" already holds that mapping. PageRun(Rec) resolves the page through GetPageID. That calls GetConditionalCardPageID, which handles Sales Header, Purchase Header, their archives, general and item journal batches and lines, requisition worksheets, and several other tables. When no conditional page applies, it falls back to the default card or lookup page. Base App's own lists call it: the Show Document actions on Sales List and Purchase List, Sales Lines (after getting the header), and Navigate for posted documents.

A hand-written case Rec."Document Type" of ... Page.Run(Page::"Sales Order", Rec) copies that mapping into a single action. The copy misses document types added later. It also bypasses routing that other extensions add through Page Management's events (OnBeforeGetConditionalCardPageID, OnAfterGetPageID, OnPageRunAtFieldOnBeforeRunPage).

Best Practice

In the list's open-document action, call PageManagement.PageRun(Rec), or PageRunModal or PageRunList as needed. PageRun returns false without opening anything when GuiAllowed is false or no page resolves. See sample: list-page-document-routing-uses-page-management.good.al.

For a new table whose rows map to different pages, register the mapping once and then use PageRun everywhere. Subscribe to OnConditionalCardPageIDNotFound, which is raised only for tables the codeunit does not route itself. Microsoft's IRS Forms and Sustainability apps register their tables this way. OnBeforeGetConditionalCardPageID is the IsHandled alternative, used by the Quality Management app.

Anti Pattern

An action trigger that switches on Document Type, or a similar type field, of a table that Page Management already routes, and calls Page.Run(Page::..., Rec) in each branch. Base App still has a few of these, for example Sales Line Archive List. The result is a duplicated mapping, not a runtime error, so report it as minor. See sample: list-page-document-routing-uses-page-management.bad.al.

Not this pattern:

  • Opening one known document type directly. Opportunity creates a quote and runs Sales Quote, and a single-type list such as Sales Order List sets CardPageID = "Sales Order".
  • A table that Page Management does not route. Assembly List switches on Assembly Header."Document Type" itself. Registering the table through OnConditionalCardPageIDNotFound is an improvement there, not a defect fix.

References