@@ -12,6 +12,7 @@ A high-performance AutoComplete component for Blazor with AI-powered semantic se
1212- ** High Performance** - Virtualization for large datasets, debounced input
1313- ** Native AOT Ready** - Source generators, zero reflection, fully trimmable
1414- ** AI Semantic Search** - Optional package with OpenAI/Azure embeddings
15+ - ** OData Integration** - Optional package for OData v3/v4 server-side filtering
1516- ** Accessible** - WCAG 2.1 AA, ARIA 1.2 Combobox pattern, keyboard navigation
1617- ** Theming** - 4 design presets (Material, Fluent, Modern, Bootstrap), CSS variables
1718- ** 8 Display Modes** - Built-in layouts eliminate template boilerplate
@@ -276,6 +277,120 @@ Or use structured `ThemeOverrides`:
276277<AutoComplete InputId="search" AriaLabel="Search products" ... />
277278```
278279
280+ ## OData Integration
281+
282+ Optional package for querying OData v3/v4 endpoints with automatic ` $filter ` generation.
283+
284+ ### Installation
285+
286+ ``` bash
287+ dotnet add package EasyAppDev.Blazor.AutoComplete.OData
288+ ```
289+
290+ ### Usage
291+
292+ ``` razor
293+ @using EasyAppDev.Blazor.AutoComplete
294+ @using EasyAppDev.Blazor.AutoComplete.OData
295+ @inject HttpClient Http
296+
297+ <AutoComplete TItem="Product"
298+ DataSource="@_odataSource"
299+ TextField="@(p => p.Name)"
300+ @bind-Value="@selectedProduct"
301+ Placeholder="Search products..." />
302+
303+ @code {
304+ private ODataDataSource<Product> _odataSource = null!;
305+ private Product? selectedProduct;
306+
307+ protected override void OnInitialized()
308+ {
309+ var options = new ODataOptions
310+ {
311+ EndpointUrl = "https://api.example.com/odata/products",
312+ FilterStrategy = ODataFilterStrategy.StartsWith,
313+ Top = 20
314+ };
315+ _odataSource = new ODataDataSource<Product>(Http, options, "Name");
316+ }
317+ }
318+ ```
319+
320+ ### Multi-Field Search
321+
322+ ``` csharp
323+ // Search across multiple fields (combined with OR)
324+ _odataSource = new ODataDataSource <Product >(
325+ Http ,
326+ options ,
327+ searchFieldNames : new [] { " Name" , " Description" , " Category" });
328+ ```
329+
330+ Generated OData: ` $filter=(startswith(tolower(Name),'search') or startswith(tolower(Description),'search') or startswith(tolower(Category),'search')) `
331+
332+ ### OData v3 Support
333+
334+ ``` csharp
335+ var options = new ODataOptions
336+ {
337+ EndpointUrl = " https://legacy-api.example.com/odata/products" ,
338+ Version = ODataVersion .V3 , // Use v3 syntax
339+ FilterStrategy = ODataFilterStrategy .Contains
340+ };
341+ ```
342+
343+ ### Filter Strategy Mapping
344+
345+ | Strategy | OData v4 | OData v3 |
346+ | ----------| ----------| ----------|
347+ | ` StartsWith ` | ` startswith(field,'value') ` | Same |
348+ | ` Contains ` | ` contains(field,'value') ` | ` substringof('value',field) ` |
349+ | ` FuzzyFallback ` | ` contains() ` + client re-rank | ` substringof() ` + client re-rank |
350+
351+ ### OData Parameters
352+
353+ | Parameter | Type | Default | Description |
354+ | -----------| ------| ---------| -------------|
355+ | ` EndpointUrl ` | ` string ` | Required | OData endpoint URL |
356+ | ` Version ` | ` ODataVersion ` | ` V4 ` | OData protocol version |
357+ | ` FilterStrategy ` | ` ODataFilterStrategy ` | ` StartsWith ` | Filter type |
358+ | ` Top ` | ` int ` | ` 100 ` | Max results ($top) |
359+ | ` Select ` | ` string[]? ` | ` null ` | Fields to return ($select) |
360+ | ` OrderBy ` | ` string? ` | ` null ` | Sort order ($orderby) |
361+ | ` AdditionalFilter ` | ` string? ` | ` null ` | Static filter ANDed with search |
362+ | ` CaseInsensitive ` | ` bool ` | ` true ` | Use tolower() wrapper |
363+ | ` MinSearchLength ` | ` int ` | ` 1 ` | Min chars before API call |
364+ | ` CustomHeaders ` | ` Dictionary<string,string>? ` | ` null ` | HTTP headers (e.g., Authorization) |
365+
366+ ### Fluent Builder
367+
368+ ``` csharp
369+ var config = AutoCompleteConfig <Product >.Create ()
370+ .WithODataSource (Http , " https://api.example.com/odata/products" , " Name" ,
371+ opts => {
372+ opts .FilterStrategy = ODataFilterStrategy .Contains ;
373+ opts .Top = 20 ;
374+ })
375+ .WithDisplayMode (ItemDisplayMode .TitleWithDescription )
376+ .Build ();
377+ ```
378+
379+ ### Service Registration
380+
381+ ``` csharp
382+ // Configuration-based
383+ builder .Services .AddAutoCompleteOData (builder .Configuration , " ODataSettings" );
384+
385+ // Explicit configuration
386+ builder .Services .AddAutoCompleteOData (
387+ " https://api.example.com/odata/products" ,
388+ options => {
389+ options .FilterStrategy = ODataFilterStrategy .Contains ;
390+ options .Top = 50 ;
391+ });
392+ ```
393+
279394## AI Semantic Search
280395
281396Optional package for meaning-based search using embeddings.
@@ -451,6 +566,7 @@ Configuration in `appsettings.json`:
451566| ` EasyAppDev.Blazor.AutoComplete ` | Core component |
452567| ` EasyAppDev.Blazor.AutoComplete.Generators ` | Source generators (build-time only) |
453568| ` EasyAppDev.Blazor.AutoComplete.AI ` | Semantic search with embeddings |
569+ | ` EasyAppDev.Blazor.AutoComplete.OData ` | OData v3/v4 server-side filtering |
454570
455571## Requirements
456572
0 commit comments