Skip to content

Commit b0a3784

Browse files
njanninkstsrki
andauthored
Autocomplete: Fix validation when bound to text (#6475)
* Autocomplete: Fix validation when bound to text * Autocomplete: Clarify documentation around validation * docs api index * formating * docs api json * move notes --------- Co-authored-by: Mladen Macanovic <mladen.macanovic@gmail.com>
1 parent 2b739d2 commit b0a3784

5 files changed

Lines changed: 86 additions & 6 deletions

File tree

Documentation/Blazorise.Docs/Pages/Docs/Extensions/Autocomplete/AutocompletePage.razor

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,17 @@
9696

9797
<DocsPageSection>
9898
<DocsPageSectionHeader Title="Validation (data annotations)">
99-
Use <Code>ValidationMode.Auto</Code> with a model decorated with data annotations to validate single and multiple selections.
99+
<Paragraph>
100+
Use <Code>ValidationMode.Auto</Code> with a model decorated with data annotations to validate single and multiple selections.
101+
</Paragraph>
102+
103+
<Paragraph>
104+
<Alert Color="Color.Info" Visible>
105+
<AlertDescription>
106+
<Strong>Note:</Strong> When both <Code>Value</Code> and <Code>Text</Code> are bound then validation will work on the <Code>Value</Code> binding.
107+
</AlertDescription>
108+
</Alert>
109+
</Paragraph>
100110
</DocsPageSectionHeader>
101111
<DocsPageSectionContent Outlined FullWidth>
102112
<AutocompleteDataAnnotationValidationExample />
@@ -189,4 +199,4 @@
189199
</DocsPageSection>
190200

191201

192-
<ComponentApiDocs ComponentTypes="[typeof(Autocomplete<,>)]" />
202+
<ComponentApiDocs ComponentTypes="[typeof(Autocomplete<,>)]" />

Documentation/Blazorise.Docs/Pages/Docs/Specifications/AutocompletePage.razor

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,4 +209,27 @@
209209
<TableRowCell></TableRowCell>
210210
</TableRow>
211211
</TableBody>
212-
</Table>
212+
</Table>
213+
214+
<DocsPageSubtitle>
215+
Validation
216+
</DocsPageSubtitle>
217+
218+
<DocsPageParagraph>
219+
The <Code>Autocomplete</Code> component supports <Code>Validation</Code> like any other regular input field. But because you can
220+
bind both the <Code>Value(s)</Code> and <Code>Text(s)</Code> properties the validation logic will work with a prioritized system
221+
for which binding expression field will be validated.
222+
223+
<OrderedList>
224+
<OrderedListItem><Code>@@bind-Value</Code> expression</OrderedListItem>
225+
<OrderedListItem><Code>@@bind-SelectedValue</Code> expression</OrderedListItem>
226+
<OrderedListItem><Code>@@bind-SelectedText</Code> expression</OrderedListItem>
227+
</OrderedList>
228+
229+
</DocsPageParagraph>
230+
231+
<DocsPageParagraph>
232+
<Strong>Note:</Strong> If you want to validate both the <Code>Value</Code> and the <Code>Text</Code> bindings then you will need
233+
to validate the text as part of the <Code>Value</Code> validation rule. Then the validation feedback will be correctly displayed
234+
on the <Code>Autocomplete</Code> component.
235+
</DocsPageParagraph>

Documentation/Blazorise.Docs/Resources/docs-api-index.json

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"generatedUtc": "2026-03-12T13:02:50.9476946Z",
2+
"generatedUtc": "2026-03-22T12:46:35.0517777Z",
33
"components": [
44
{
55
"type": "global::Blazorise.Abbreviation",
@@ -5027,6 +5027,14 @@
50275027
"summary": "Gets or sets the currently selected item text.",
50285028
"isBlazoriseEnum": false
50295029
},
5030+
{
5031+
"name": "SelectedTextExpression",
5032+
"type": "Expression<>",
5033+
"typeName": "Expression<Func<string>>",
5034+
"defaultValue": "null",
5035+
"summary": "Gets or sets an expression that identifies the selected text.",
5036+
"isBlazoriseEnum": false
5037+
},
50305038
{
50315039
"name": "SelectedTexts",
50325040
"type": "List<>",
@@ -5035,6 +5043,14 @@
50355043
"summary": "Currently selected items texts. Used when multiple selection is set.",
50365044
"isBlazoriseEnum": false
50375045
},
5046+
{
5047+
"name": "SelectedTextsExpression",
5048+
"type": "Expression<>",
5049+
"typeName": "Expression<Func<List<string>>>",
5050+
"defaultValue": "null",
5051+
"summary": "Gets or sets an expression that identifies the selected texts. Used when multiple selection is set.",
5052+
"isBlazoriseEnum": false
5053+
},
50385054
{
50395055
"name": "SelectedValue",
50405056
"type": "object",

Documentation/Blazorise.Docs/Resources/docs-index.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"generatedUtc": "2026-03-20T07:56:22.7501273Z",
2+
"generatedUtc": "2026-03-22T12:55:30.7622376Z",
33
"pages": [
44
{
55
"route": "/docs",
@@ -3911,7 +3911,7 @@
39113911
"sourcePath": "Pages/Docs/Extensions/Autocomplete/Examples/AutocompleteDataAnnotationValidationExample.razor",
39123912
"content": "@using System.ComponentModel.DataAnnotations\r\n\r\n<Validations Mode=\"ValidationMode.Auto\" Model=\"@model\">\r\n <Validation>\r\n <Field>\r\n <FieldLabel>Country</FieldLabel>\r\n <FieldBody>\r\n <Autocomplete TItem=\"Country\"\r\n TValue=\"string\"\r\n Data=\"@Countries\"\r\n TextField=\"@(( item ) => item.Name)\"\r\n ValueField=\"@(( item ) => item.Iso)\"\r\n Placeholder=\"Select a country\"\r\n @bind-SelectedValue=\"@model.CountryIso\">\r\n <Feedback>\r\n <ValidationError />\r\n </Feedback>\r\n </Autocomplete>\r\n </FieldBody>\r\n </Field>\r\n </Validation>\r\n <Validation>\r\n <Field>\r\n <FieldLabel>Countries</FieldLabel>\r\n <FieldBody>\r\n <Autocomplete TItem=\"Country\"\r\n TValue=\"string\"\r\n Data=\"@Countries\"\r\n TextField=\"@(( item ) => item.Name)\"\r\n ValueField=\"@(( item ) => item.Iso)\"\r\n SelectionMode=\"AutocompleteSelectionMode.Multiple\"\r\n Placeholder=\"Select countries\"\r\n @bind-SelectedValues=\"@model.CountryIsos\">\r\n <Feedback>\r\n <ValidationError />\r\n </Feedback>\r\n </Autocomplete>\r\n </FieldBody>\r\n </Field>\r\n </Validation>\r\n</Validations>\r\n\r\n@code {\r\n [Inject]\r\n public CountryData CountryData { get; set; }\r\n\r\n public IEnumerable<Country> Countries;\r\n\r\n AutocompleteValidationModel model = new AutocompleteValidationModel();\r\n\r\n protected override async Task OnInitializedAsync()\r\n {\r\n Countries = await CountryData.GetDataAsync();\r\n await base.OnInitializedAsync();\r\n }\r\n\r\n public class AutocompleteValidationModel\r\n {\r\n [Required( ErrorMessage = \"Please select a country.\" )]\r\n public string CountryIso { get; set; }\r\n\r\n [MinLength( 1, ErrorMessage = \"Please select at least one country.\" )]\r\n public List<string> CountryIsos { get; set; } = new List<string>();\r\n }\r\n}",
39133913
"title": "Validation (data annotations)",
3914-
"description": "Use ValidationMode.Auto with a model decorated with data annotations to validate single and multiple selections."
3914+
"description": "Use ValidationMode.Auto with a model decorated with data annotations to validate single and multiple selections. Note: When both Value and Text are bound then validation will work on the Value binding."
39153915
},
39163916
{
39173917
"code": "AutocompleteReadDataExample",

Source/Extensions/Blazorise.Components/Autocomplete.razor.cs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,11 @@ public partial class Autocomplete<TItem, TValue>
101101
/// </summary>
102102
protected ComponentParameterInfo<string> paramSelectedText;
103103

104+
/// <summary>
105+
/// Captured SelectedTextExpression parameter snapshot.
106+
/// </summary>
107+
protected ComponentParameterInfo<Expression<Func<string>>> paramSelectedTextExpression;
108+
104109
/// <summary>
105110
/// Captured SelectedValues parameter snapshot.
106111
/// </summary>
@@ -111,6 +116,11 @@ public partial class Autocomplete<TItem, TValue>
111116
/// </summary>
112117
protected ComponentParameterInfo<IEnumerable<string>> paramSelectedTexts;
113118

119+
/// <summary>
120+
/// Captured SelectedTextExpression parameter snapshot.
121+
/// </summary>
122+
protected ComponentParameterInfo<Expression<Func<List<string>>>> paramSelectedTextsExpression;
123+
114124
/// <summary>
115125
/// Captured Data parameter snapshot.
116126
/// </summary>
@@ -153,6 +163,8 @@ protected override void CaptureParameters( ParameterView parameters )
153163
parameters.TryGetParameter( Data, value => data.IsEqual( value ), out paramData );
154164
parameters.TryGetParameter( SelectedValueExpression, out paramSelectedValueExpression );
155165
parameters.TryGetParameter( SelectedValuesExpression, out paramSelectedValuesExpression );
166+
parameters.TryGetParameter( SelectedTextExpression, out paramSelectedTextExpression );
167+
parameters.TryGetParameter( SelectedTextsExpression, out paramSelectedTextsExpression );
156168
}
157169

158170
/// <inheritdoc/>
@@ -230,6 +242,10 @@ protected override async Task OnAfterSetParametersAsync( ParameterView parameter
230242
{
231243
await ParentValidation.InitializeInputExpression( paramSelectedValuesExpression.Value );
232244
}
245+
else if ( paramSelectedTextsExpression.Defined )
246+
{
247+
await ParentValidation.InitializeInputExpression( paramSelectedTextsExpression.Value );
248+
}
233249
}
234250
else
235251
{
@@ -241,6 +257,10 @@ protected override async Task OnAfterSetParametersAsync( ParameterView parameter
241257
{
242258
await ParentValidation.InitializeInputExpression( paramSelectedValueExpression.Value );
243259
}
260+
else if ( paramSelectedTextExpression.Defined )
261+
{
262+
await ParentValidation.InitializeInputExpression( paramSelectedTextExpression.Value );
263+
}
244264
}
245265

246266
await InitializeValidation();
@@ -1781,6 +1801,11 @@ public Expression<Func<TValue>> SelectedValueExpression
17811801
[Parameter]
17821802
public string SelectedText { get; set; }
17831803

1804+
/// <summary>
1805+
/// Gets or sets an expression that identifies the selected text.
1806+
/// </summary>
1807+
[Parameter] public Expression<Func<string>> SelectedTextExpression { get; set; }
1808+
17841809
/// <summary>
17851810
/// Gets or sets the currently selected item text.
17861811
/// </summary>
@@ -1915,6 +1940,12 @@ public List<string> SelectedTexts
19151940
set => selectedTextsParam = ( value == null ? null : new( value ) );
19161941
}
19171942

1943+
/// <summary>
1944+
/// Gets or sets an expression that identifies the selected texts.
1945+
/// Used when multiple selection is set.
1946+
/// </summary>
1947+
[Parameter] public Expression<Func<List<string>>> SelectedTextsExpression { get; set; }
1948+
19181949
/// <summary>
19191950
/// Occurs after the selected texts have changed.
19201951
/// Used when multiple selection is set.

0 commit comments

Comments
 (0)