---
title: Locate a menu item for navigation
summary: Locates a menu item within a category for navigation rendering, trying an exact link match before falling back to a query-string-insensitive match. Purely in-memory — no database access.
status: draft
owner: SAIF Doc Gen
last_reviewed: 2026-08-17
library: SAIF.Business.Menu
reference_type: package
operation_id: OP-MENU-03
trigger: Menu/navigation rendering — a category-scoped page lookup
---

# Locate a menu item for navigation

Locates a menu item within a category for navigation rendering, trying an exact link match before falling back to a query-string-insensitive match. Purely in-memory — no database access.

| Field | Value |
| --- | --- |
| **Operation ID** | OP-MENU-03 |
| **Trigger** | Menu/navigation rendering — a category-scoped page lookup |
| **Inputs** | Application code, category code, page link, optional visible-only flag |
| **Outputs** | The matching `clsMenuAuthorizedItem`, or `Nothing` |
| **Primary components** | `clsMenuAuthorizedItemCollection.Item`, `ItemExact`, `ItemByCategory` |
| **Entry point** | `SAIF.Business.Menu/clsMenuAuthorizedItemCollection.vb` |

## Steps

Ordered steps for `ItemByCategory`, the widest of the three lookups:

1. Filter on category code plus an exact upper-cased page link, optionally requiring `IsVisible`. ([BR-MENU-010](../business-rules.md#br-menu-010-visible-only-lookups), [BR-MENU-011](../business-rules.md#br-menu-011-category-lookup-fallback))
2. If any match is found, return the first one.
3. Otherwise re-filter using `LinkOnly` on both sides (query strings ignored) and return the first match, or `Nothing`. ([BR-MENU-009](../business-rules.md#br-menu-009-page-link-normalization))
   - Note: the second filter appends into the **same** `items` collection that the first pass already populated, so the fallback result set includes any earlier matches.*
4. `Item(appCode, category, pageLink, visibleOnly)` applies application + category + link-only matching in a single pass; `ItemExact` applies application + category + full-link matching. All three return `Nothing` when nothing matches.

## Process flow

```mermaid
flowchart TD
    Start([Navigation lookup requested]) --> Exact[Filter: category + exact upper-cased page link]
    Exact --> Found1{Match found?}
    Found1 -->|Yes| Return([Return first match])
    Found1 -->|No| Fallback[Re-filter with LinkOnly, query string ignored]
    Fallback --> Found2{Match found?}
    Found2 -->|Yes| Return
    Found2 -->|No| Nothing([Return Nothing])
```

## Failure and edge-case behavior
- No match in either pass: `Nothing` is returned and the caller treats this as "not found".
- The fallback pass accumulates into the same result collection as the first pass, so ordering of a fallback result set may include earlier exact matches.*

## Related documentation
- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)
- [SQL catalog](../sql/index.md)
- [Database tables](../database-tables.md)

> **Note:** Statements marked with `*` were inferred from code structure, naming conventions, or contextual evidence where direct confirmation was not available in source artifacts.

## Sources
- SAIF.Business.Menu/clsMenuAuthorizedItemCollection.vb
