Skip to content

Commit 458a539

Browse files
committed
Add InputList component and samples
1 parent 09a777c commit 458a539

13 files changed

Lines changed: 876 additions & 0 deletions

File tree

samples/Sample.Core/Pages/Index.razor

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
<h2>DateTimePicker</h2>
2121
<p><a href="/datetimepicker/index">Date Time Picker Control Demo</a></p>
2222

23+
<h2>InputList</h2>
24+
<p><a href="/inputlist/index">InputList Control Demo</a></p>
25+
2326
<h2>Typeahead</h2>
2427
<p><a href="/typeahead/index">Typeahead Control Demo</a> </p>
2528

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<h3>Basic</h3>
2+
3+
<p>Basic example of binding to a string list.</p>
4+
5+
<InputList @bind-Value="Tags" />
6+
7+
<p>Bound Value: @string.Join(", ", Tags)</p>
8+
9+
<pre><code class="language-markup">&lt;InputList @@bind-Value=&quot;Tags&quot; /&gt;</code></pre>
10+
11+
<pre><code class="language-csharp">@@code {
12+
public IList&lt;string&gt; Tags { get; set; } = new List&lt;string&gt; { &quot;Blazor&quot;, &quot;Components&quot; };
13+
}</code></pre>
14+
15+
@code {
16+
public IList<string> Tags { get; set; } = new List<string> { "Blazor", "Components" };
17+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<h3>Default New Item</h3>
2+
3+
<p>Use <code>NewItemValue</code> or <code>NewItemFactory</code> to configure the value added by the add button.</p>
4+
5+
<InputList TValue="string"
6+
@bind-Value="Emails"
7+
InputType="email"
8+
NewItemValue="@NewEmailValue"
9+
InputClass="form-control"
10+
AddClass="btn btn-outline-primary"
11+
RemoveClass="btn btn-outline-danger"
12+
RemoveTitle="Remove email">
13+
<RemoveContent>
14+
<i class="bi bi-trash" aria-hidden="true"></i>
15+
</RemoveContent>
16+
</InputList>
17+
18+
<p>Emails: @string.Join(", ", Emails)</p>
19+
20+
<pre><code class="language-markup">&lt;InputList @@bind-Value=&quot;Emails&quot;
21+
InputType=&quot;email&quot;
22+
NewItemValue=&quot;new.user@example.com&quot;
23+
RemoveTitle=&quot;Remove email&quot;&gt;
24+
&lt;RemoveContent&gt;
25+
&lt;i class=&quot;bi bi-trash&quot; aria-hidden=&quot;true&quot;&gt;&lt;/i&gt;
26+
&lt;/RemoveContent&gt;
27+
&lt;/InputList&gt;</code></pre>
28+
29+
@code {
30+
public string NewEmailValue { get; set; } = "new.user@example.com";
31+
32+
public IList<string> Emails { get; set; } = new List<string>
33+
{
34+
"support@example.com",
35+
"sales@example.com"
36+
};
37+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<h3>Numbers and Dates</h3>
2+
3+
<p>InputList infers HTML input types from the item type.</p>
4+
5+
<div class="row">
6+
<div class="col-md-6">
7+
<h4>Numbers</h4>
8+
<InputList @bind-Value="Scores"
9+
InputClass="form-control"
10+
AddClass="btn btn-outline-primary"
11+
RemoveClass="btn btn-outline-danger"
12+
NewItemValue="100" />
13+
<p>Scores: @string.Join(", ", Scores)</p>
14+
</div>
15+
<div class="col-md-6">
16+
<h4>Dates</h4>
17+
<InputList @bind-Value="Milestones"
18+
InputClass="form-control"
19+
AddClass="btn btn-outline-primary"
20+
RemoveClass="btn btn-outline-danger"
21+
NewItemFactory="CreateMilestone" />
22+
<p>Milestones: @string.Join(", ", Milestones.Select(d => d.ToShortDateString()))</p>
23+
</div>
24+
</div>
25+
26+
<pre><code class="language-markup">&lt;InputList @@bind-Value=&quot;Scores&quot; NewItemValue=&quot;100&quot; /&gt;
27+
&lt;InputList @@bind-Value=&quot;Milestones&quot; NewItemFactory=&quot;CreateMilestone&quot; /&gt;</code></pre>
28+
29+
@code {
30+
public IList<int> Scores { get; set; } = new List<int> { 85, 92, 100 };
31+
32+
public IList<DateOnly> Milestones { get; set; } = new List<DateOnly>
33+
{
34+
DateOnly.FromDateTime(DateTime.Today),
35+
DateOnly.FromDateTime(DateTime.Today.AddDays(7))
36+
};
37+
38+
public DateOnly CreateMilestone()
39+
=> DateOnly.FromDateTime(DateTime.Today);
40+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<h3>Update On Input</h3>
2+
3+
<p>Set <code>UpdateOnInput</code> to update the bound list while typing.</p>
4+
5+
<InputList @bind-Value="Items"
6+
UpdateOnInput="true"
7+
InputClass="form-control"
8+
AddClass="btn btn-outline-primary"
9+
RemoveClass="btn btn-outline-danger" />
10+
11+
<p>Bound Value: @string.Join(", ", Items)</p>
12+
13+
<pre><code class="language-markup">&lt;InputList @@bind-Value=&quot;Items&quot; UpdateOnInput=&quot;true&quot; /&gt;</code></pre>
14+
15+
@code {
16+
public IList<string> Items { get; set; } = new List<string> { "Alpha", "Beta" };
17+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
@using System.ComponentModel.DataAnnotations
2+
3+
<h3>Validation</h3>
4+
5+
<p>InputList supports standard validation through EditContext and applies validation styles to the overall input container.</p>
6+
7+
<EditForm Model="Profile" OnValidSubmit="HandleValidSubmit">
8+
<DataAnnotationsValidator />
9+
<ValidationSummary />
10+
11+
<div class="mb-3">
12+
<label for="Aliases">Aliases *</label>
13+
<InputList id="Aliases"
14+
@bind-Value="Profile.Aliases"
15+
InputClass="form-control"
16+
AddClass="btn btn-outline-primary"
17+
RemoveClass="btn btn-outline-danger" />
18+
<ValidationMessage For="@(() => Profile.Aliases)" />
19+
</div>
20+
21+
<button type="submit" class="btn btn-primary">Submit</button>
22+
</EditForm>
23+
24+
@if (Submitted)
25+
{
26+
<p class="mt-3">Form submitted successfully.</p>
27+
}
28+
29+
<pre><code class="language-markup">&lt;EditForm Model=&quot;Profile&quot; OnValidSubmit=&quot;HandleValidSubmit&quot;&gt;
30+
&lt;DataAnnotationsValidator /&gt;
31+
&lt;InputList @@bind-Value=&quot;Profile.Aliases&quot; /&gt;
32+
&lt;ValidationMessage For=&quot;@@(() =&gt; Profile.Aliases)&quot; /&gt;
33+
&lt;/EditForm&gt;</code></pre>
34+
35+
@code {
36+
public AliasProfile Profile { get; set; } = new();
37+
38+
public bool Submitted { get; set; }
39+
40+
private void HandleValidSubmit()
41+
=> Submitted = true;
42+
43+
public class AliasProfile
44+
{
45+
[Required]
46+
[MinLength(1, ErrorMessage = "At least one alias is required.")]
47+
public IList<string> Aliases { get; set; } = new List<string>();
48+
}
49+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
@page "/inputlist/index"
2+
@using Sample.Core.Pages.InputList.Examples
3+
4+
<h1>InputList</h1>
5+
6+
<p>List Input Control</p>
7+
8+
<Instructions></Instructions>
9+
10+
<h2 class="mb-3">Examples</h2>
11+
12+
<Basic />
13+
14+
<div class="mb-5"></div>
15+
16+
<NumbersAndDates />
17+
18+
<div class="mb-5"></div>
19+
20+
<UpdateOnInput />
21+
22+
<div class="mb-5"></div>
23+
24+
<DefaultValue />
25+
26+
<div class="mb-5"></div>
27+
28+
<Validation />
29+
30+
@code {
31+
32+
}

samples/Sample.Core/Shared/MainMenu.razor

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
<NavLink class="dropdown-item" href="/conditional/index" Match="NavLinkMatch.Prefix">Conditional</NavLink>
4242
<NavLink class="dropdown-item" href="/busybutton/index" Match="NavLinkMatch.Prefix">BusyButton</NavLink>
4343
<NavLink class="dropdown-item" href="/repeater/index" Match="NavLinkMatch.Prefix">Repeater</NavLink>
44+
<NavLink class="dropdown-item" href="/inputlist/index" Match="NavLinkMatch.Prefix">InputList</NavLink>
4445
<NavLink class="dropdown-item" href="/inputimage/index" Match="NavLinkMatch.Prefix">InputImage</NavLink>
4546
<NavLink class="dropdown-item" href="/culture/index" Match="NavLinkMatch.Prefix">LocalTime</NavLink>
4647
</div>
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
@namespace LoreSoft.Blazor.Controls
2+
@typeparam TValue
3+
4+
<div @attributes="ContainerAttributes" class="@ContainerClass()">
5+
@for (var index = 0; index < CurrentValue.Count; index++)
6+
{
7+
var itemIndex = index;
8+
var item = CurrentValue[itemIndex];
9+
10+
<div class="input-list-item">
11+
<input type="@EffectiveInputType"
12+
class="@ItemInputClass()"
13+
value="@FormatValue(item)"
14+
disabled="@Disabled"
15+
@oninput="args => HandleInput(itemIndex, args)"
16+
@onchange="args => HandleChange(itemIndex, args)" />
17+
18+
<button type="button"
19+
class="@RemoveButtonClass()"
20+
title="@RemoveTitle"
21+
disabled="@Disabled"
22+
@onclick="() => RemoveItem(itemIndex)">
23+
@if (RemoveContent is not null)
24+
{
25+
@RemoveContent
26+
}
27+
else
28+
{
29+
@RemoveText
30+
}
31+
</button>
32+
</div>
33+
}
34+
35+
<button type="button"
36+
class="@AddButtonClass()"
37+
title="@AddTitle"
38+
disabled="@Disabled"
39+
@onclick="AddItem">
40+
@if (AddContent is not null)
41+
{
42+
@AddContent
43+
}
44+
else
45+
{
46+
@AddText
47+
}
48+
</button>
49+
</div>

0 commit comments

Comments
 (0)