Skip to content

Commit

Permalink
MudFileUpload: Improve validation in MudForm (MudBlazor#7720)
Browse files Browse the repository at this point in the history
* MudFileUpload: Allow clearing FileUpload by setting `Files` to null

Builds upon MudBlazor#7578 to flesh out form validation on `MudFileUpload` by
allowing users to clear a `MudFileUpload` instance by setting `Files` to
`null`. This would previously not trigger form validation or it would
not mark the `MudFileUpload` instance as `Touched`.

* WIP `ClearAsync` + `FileUploadButtonTemplateContext` implementations

* Add/Update documentation and tests
  • Loading branch information
igotinfected authored Nov 8, 2023
1 parent 4e07fa4 commit 59f7e62
Show file tree
Hide file tree
Showing 24 changed files with 562 additions and 104 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
Variant="Variant.Filled"
Color="Color.Primary"
StartIcon="@Icons.Material.Filled.CloudUpload"
for="@context">
for="@context.Id">
AppendMultipleFiles = true
</MudButton>
</ButtonTemplate>
Expand All @@ -31,7 +31,7 @@
Variant="Variant.Filled"
Color="Color.Primary"
StartIcon="@Icons.Material.Filled.CloudUpload"
for="@context">
for="@context.Id">
AppendMultipleFiles = false
</MudButton>
</ButtonTemplate>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
Variant="Variant.Filled"
Color="Color.Primary"
StartIcon="@Icons.Material.Filled.CloudUpload"
for="@context">
for="@context.Id">
Upload Files
</MudButton>
</ButtonTemplate>
Expand All @@ -18,7 +18,7 @@
Color="Color.Secondary"
Icon="@Icons.Material.Filled.Image"
Label="Load picture"
for="@context" />
for="@context.Id" />
</ButtonTemplate>
</MudFileUpload>

Expand All @@ -27,7 +27,7 @@
<MudFab HtmlTag="label"
Color="Color.Success"
Icon="@Icons.Material.Filled.AttachFile"
for="@context" />
for="@context.Id" />
</ButtonTemplate>
</MudFileUpload>

Expand All @@ -36,7 +36,7 @@
<MudIconButton HtmlTag="label"
Color="Color.Info"
Icon="@Icons.Material.Filled.PhotoCamera"
for="@context">
for="@context.Id">
</MudIconButton>
</ButtonTemplate>
</MudFileUpload>
Expand All @@ -46,7 +46,7 @@
<MudButton HtmlTag="label"
Variant="Variant.Filled"
Color="Color.Primary"
for="@context">
for="@context.Id">
Disabled Button
</MudButton>
</ButtonTemplate>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
@namespace MudBlazor.Docs.Examples

@inject ISnackbar Snackbar

<MudStack Style="width: 100%">
<MudFileUpload T="IReadOnlyList<IBrowserFile>"
AppendMultipleFiles
OnFilesChanged="OnInputFileChanged"
Hidden="@false"
InputClass="absolute mud-width-full mud-height-full overflow-hidden z-20"
InputStyle="opacity:0"
@ondragenter="@SetDragClass"
@ondragleave="@ClearDragClass"
@ondragend="@ClearDragClass">
<ButtonTemplate>
<MudPaper Height="300px"
Outlined="true"
Class="@_dragClass">
<MudText Typo="Typo.h6">
Drag and drop files here or click
</MudText>
@foreach (var file in _fileNames)
{
<MudChip Color="Color.Dark" Text="@file" />
}
</MudPaper>
<MudToolBar DisableGutters="true"
Class="relative d-flex justify-end gap-4 z-30">
<MudButton HtmlTag="label"
Color="Color.Primary"
for="@context.Id"
Variant="Variant.Filled">
Open file picker
</MudButton>
<MudButton OnClick="@Upload"
Color="Color.Primary"
Disabled="@(!_fileNames.Any())"
Variant="Variant.Filled">
Upload
</MudButton>
<MudButton OnClick="@Clear"
Color="Color.Error"
Disabled="@(!_fileNames.Any())"
Variant="Variant.Filled">
Clear
</MudButton>
</MudToolBar>
</ButtonTemplate>
</MudFileUpload>
</MudStack>

@code {
#nullable enable
private const string DefaultDragClass = "relative rounded-lg border-2 border-dashed pa-4 mt-4 mud-width-full mud-height-full z-10";
private string _dragClass = DefaultDragClass;
private readonly List<string> _fileNames = new();

private async Task Clear()
{
_fileNames.Clear();
ClearDragClass();
await Task.Delay(100);
}

private void OnInputFileChanged(InputFileChangeEventArgs e)
{
ClearDragClass();
var files = e.GetMultipleFiles();
foreach (var file in files)
{
_fileNames.Add(file.Name);
}
}

private void Upload()
{
// Upload the files here
Snackbar.Configuration.PositionClass = Defaults.Classes.Position.TopCenter;
Snackbar.Add("TODO: Upload your files!");
}

private void SetDragClass()
=> _dragClass = $"{DefaultDragClass} mud-border-primary";

private void ClearDragClass()
=> _dragClass = DefaultDragClass;
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
@using System.IO
@using System.Text
@using System.Threading
@using FluentValidation

@namespace MudBlazor.Docs.Examples

@inject ISnackbar Snackbar

<MudStack Style="width: 100%">
<MudForm Model="@_model"
@bind-IsValid="_isValid"
@bind-IsTouched="_isTouched"
Validation="@_validationRules.ValidateValue">
<MudItem xs="12">
<MudFileUpload T="IReadOnlyList<IBrowserFile>"
AppendMultipleFiles
@bind-Files="_model.Files"
@bind-Files:after="@ClearDragClass"
For="@(() => _model.Files)"
Hidden="@false"
InputClass="absolute mud-width-full mud-height-full overflow-hidden z-20"
InputStyle="opacity:0"
@ondragenter="@SetDragClass"
@ondragleave="@ClearDragClass"
@ondragend="@ClearDragClass">
<ButtonTemplate>
<MudPaper Height="300px"
Outlined="true"
Class="@_dragClass">
<MudText Typo="Typo.h6">
Drag and drop files here or click
</MudText>
@foreach (var file in _model.Files?.Select(file => file.Name) ?? Enumerable.Empty<string>())
{
<MudChip Color="Color.Dark"
Text="@file" />
}
</MudPaper>
<MudToolBar DisableGutters="true"
Class="relative d-flex justify-end gap-4 z-30">
<MudButton HtmlTag="label"
Color="Color.Primary"
for="@context.Id"
Variant="Variant.Filled">
Open file picker
</MudButton>
<MudButton OnClick="@Upload"
Color="Color.Primary"
Disabled="@(!_isValid || !_isTouched || _model.Files is null || !_model.Files.Any())"
Variant="Variant.Filled">
Upload
</MudButton>
<MudButton OnClick="@context.Actions.ClearAsync"
Color="Color.Error"
Disabled="@(_model.Files is null || !_model.Files.Any())"
Variant="Variant.Filled">
Clear
</MudButton>
</MudToolBar>
</ButtonTemplate>
</MudFileUpload>
</MudItem>
<MudItem xs="12">
IsValid: @_isValid - IsTouched: @_isTouched
</MudItem>
</MudForm>
</MudStack>

@code {
#nullable enable
public class Model
{
public IReadOnlyList<IBrowserFile>? Files { get; set; } = new List<IBrowserFile>();
}

private Model _model = new();
private ModelFluentValidator _validationRules = new();
private bool _isValid;
private bool _isTouched;
private const string FileContent = "this is content";
private const string DefaultDragClass = "relative rounded-lg border-2 border-dashed pa-4 mt-4 mud-width-full mud-height-full z-10";
private string _dragClass = DefaultDragClass;

private void Upload()
{
// Upload the files here
Snackbar.Configuration.PositionClass = Defaults.Classes.Position.TopCenter;
Snackbar.Add("TODO: Upload your files!");
}

private void SetDragClass()
=> _dragClass = $"{DefaultDragClass} mud-border-primary";

private void ClearDragClass()
=> _dragClass = DefaultDragClass;

public class ModelFluentValidator : AbstractValidator<Model>
{
public ModelFluentValidator()
{
RuleFor(x => x.Files)
.NotEmpty()
.WithMessage("There must be at least 1 file.");
}

public Func<object, string, Task<IEnumerable<string>>> ValidateValue => async (model, propertyName) =>
{
var result = await ValidateAsync(ValidationContext<Model>.CreateWithOptions((Model)model, x => x.IncludeProperties(propertyName)));
return result.IsValid ? Array.Empty<string>() : result.Errors.Select(e => e.ErrorMessage);
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
Variant="Variant.Filled"
Color="Color.Primary"
StartIcon="@Icons.Material.Filled.CloudUpload"
for="@context">
for="@context.Id">
Upload using FileValueChanged
</MudButton>
</ButtonTemplate>
Expand All @@ -18,7 +18,7 @@
Variant="Variant.Filled"
Color="Color.Primary"
StartIcon="@Icons.Material.Filled.CloudUpload"
for="@context">
for="@context.Id">
Upload using OnFilesChanged
</MudButton>
</ButtonTemplate>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
Variant="Variant.Filled"
Color="Color.Primary"
StartIcon="@Icons.Material.Filled.CloudUpload"
for="@context">
for="@context.Id">
Multiple Files
</MudButton>
</ButtonTemplate>
Expand All @@ -18,7 +18,7 @@
Variant="Variant.Filled"
Color="Color.Primary"
StartIcon="@Icons.Material.Filled.CloudUpload"
for="@context">
for="@context.Id">
Only .pdf files
</MudButton>
</ButtonTemplate>
Expand All @@ -31,7 +31,7 @@
Variant="Variant.Filled"
Color="Color.Primary"
StartIcon="@Icons.Material.Filled.CloudUpload"
for="@context">
for="@context.Id">
Only image files
</MudButton>
</ButtonTemplate>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<MudButton HtmlTag="label"
Variant="Variant.Filled"
Color="Color.Primary"
for="@context">
for="@context.Id">
Single File
</MudButton>
</ButtonTemplate>
Expand All @@ -26,7 +26,7 @@
<MudButton HtmlTag="label"
Variant="Variant.Filled"
Color="Color.Secondary"
for="@context">
for="@context.Id">
Multiple Files
</MudButton>
</ButtonTemplate>
Expand Down
Loading

0 comments on commit 59f7e62

Please sign in to comment.