← All entries

Filtering a lookup field by a choice field value (model-driven forms)

Praxisis D365 Wiki · Public reference · Client-specific details redacted

Source: Claude.ai chat (original: lookup-field-filtering-by-choice-field__4b8a9ac1.md) Added: 2026-10-02

Summary

  • The no-code "Filter by related records" option in the form designer works lookup-to-lookup only — not choice-to-lookup.
  • For choice-filtered lookups, write a small JS web resource using addPreSearch + addCustomFilter. addPreSearch runs on every lookup open (always reads current choice value); addCustomFilter filters within existing views (does NOT replace them — use addCustomView for fully separate view/columns).
  • No-code alternative: replace the choice field with a lookup to a small Category config table + give the target table the same Category lookup + enable "Filter by related records" declaratively. Trades a field type for a model change — only worth it early in a build.

Key takeaways

  • Clear the lookup on choice change (setValue(null)) to avoid saving a mismatched pair.
  • If the target table's choice is a global choice shared with the form's field, integer values match directly. Otherwise map them in code.
  • Register handlers with "Pass execution context as first parameter" ticked on both.

Learnings / how to apply

  • Codify this as a reusable JS web-resource pattern (per-form namespace, applyFilter + onLoad + onChoiceChange) — standard Praxisis Dynamics UX pattern.
  • When scoping new forms, prefer the no-code lookup-to-lookup pattern unless the choice is truly immutable (small, closed vocabulary).

Bonus (related in same chat): Volunteer / Event Signup Data Model (Shift / Shift Location / Shift Application)

  • Minimum tables: Shift (period/duration template) → Shift Location (junction, carries capacity + status + current signup count) → Shift Application (signup, lookup to Location + Shift Location + applicant details).
  • Location/Community must be a table, not a choice — the cascading filter needs lookup-to-lookup.
  • A denormalised Location lookup on Shift Application is redundant but needed for the cascading filter. Have a Power Automate flow overwrite it from the parent so it can never drift.
  • Don't use a rollup for Signup Count — 12-hr default recalc leaves the slot open long after it's full. Instead use a flow on Shift Application create / status change: count applications on parent with counted statuses → update Signup Count → deactivate at capacity → reactivate on cancellation.
  • Concurrency gap: two anonymous submits within the same second both pass. If overbooking by one is unacceptable → add a Pre-Operation plugin on Shift Application create that re-checks count vs. max and throws (Power Pages surfaces the error on the form).
  • Anonymous web role table permissions (global scope): Shift Application = Create only, Shift Location = Read, Location = Read. Keep Web API disabled for these tables — anonymous Read + Web API = anyone enumerates everything incl. admin fields.
  • Dedupe: alternate key on (email + shiftlocationid) so a second submit fails, OR a flow that cancels duplicates.
  • Alternative UX worth considering: 3-page flow (list of Locations → list of Shift Locations for that Location → create form with Shift Location + Location pre-filled from query string). Removes the lookup modal entirely (modals are the weakest part of anonymous forms on mobile), shows availability before commit, needs no filtering config.

Learnings / how to apply

  • "Capacity management via flow, not rollup" is the Praxisis default pattern for any real-time inventory / signup / booking.
  • Codify the 3-page alternative in a Praxisis Power Pages "Anonymous Signup Flow" starter template — eliminates most of the mobile-UX pain in one design decision.

Need this applied to your own tenant?

Praxisis Sustain Self-Serve builds a private AI Wiki trained on your documents and tickets, with free Tier-2 support when the AI cannot answer. Book a 30-min overview.