I found this great post by Chris Sainty: Creating Bespoke Input Components for Blazor from Scratch. It is exactly what I need, but not with string
, but with uploaded files IBrowserFile
. So I have adapted and extended the example for me. The customized component displays the new files and saves it in my model, but in the CSS the status unfortunately stays on class="modified invalid"
.
I must be missing a small detail here. What is it? Thanks in advance for any hints.
Here is my code reduced to the essentials.
Selection.razor
@page "/selection"
@inherits ParentComponent<SelectionTestModel>
<PageComponent @ref="Page" Model="Model" StatusCode="StatusCode" PageType="PageType.Touch">
<PageBody>
<EditForm Model="Model" OnValidSubmit="Save">
<DataAnnotationsValidator />
<DocumentComponent @ref="DocumentUpload" @bind-Documents="Model.Files" />
</EditForm>
</PageBody>
</PageComponent>
@code {
private DocumentComponent DocumentUpload;
}
SelectionTestModel.cs
public class SelectionTestModel
{
public int? KeyID { get; set; }
/* ... */
[System.ComponentModel.DisplayName("Document")]
[System.ComponentModel.DataAnnotations.Display(Name = "Document")]
[System.ComponentModel.DataAnnotations.Range(2, 2, ErrorMessage = "You have to bring exactly two files!")]
public List<DocumentModel> Files { get; set; } = new List<DocumentModel>();
}
DocumentModel
public class DocumentModel
{
public int? Id { get; set; }
public string Reference { get; set; }
public string Name { get; set; }
public long Size { get; set; }
public string ContentType { get; set; }
public string Content { get; set; } /*file as base64 string*/
}
DocumentComponent.razor
@using System.Linq.Expressions
<div class="dropzone rounded @_dropClass @_validClass">
<InputFile id="inputDrop" multiple
ondragover="event.preventDefault()"
ondragstart="event.dataTransfer.setData('', event.target.id)"
accept="@AllowedFileTypes"
OnChange="OnInputFileChange"
@ondragenter="HandleDragEnter"
@ondragleave="HandleDragLeave" />
@*...*@
</div>
@code {
[CascadingParameter] public EditContext EditContext { get; set; }
[Parameter] public List<DocumentModel> Documents { get; set; } = new List<DocumentModel>();
[Parameter] public EventCallback<List<DocumentModel>> DocumentsChanged { get; set; }
[Parameter] public Expression<Func<List<DocumentModel>>> DocumentsExpression { get; set; }
/*...*/
public List<string> AllowedFileTypes { get; set; } = new List<string> { ".pdf", /*...*/ };
private FieldIdentifier _fieldIdentifier;
private string _validClass => EditContext?.FieldCssClass(_fieldIdentifier) ?? null;
protected override void OnInitialized()
{
base.OnInitialized();
_fieldIdentifier = FieldIdentifier.Create(DocumentsExpression);
}
private async Task OnInputFileChange(InputFileChangeEventArgs e)
{
// validation: do we accept the file (content type, amount of files, size)
if (e.FileCount == 1) // keep it simple for this example
{
// read from IBrowserFile and return DocumentModel in memory only
Documents.Add(await SaveFile(e.File));
await DocumentsChanged.InvokeAsync(Documents);
EditContext?.NotifyFieldChanged(_fieldIdentifier);
}
}
/*...*/
}
How does it behave in the browser (Chrome)
After loading the page everything looks as expected.
After that I upload a single file. So I have one file and I expect two. The validation turns red and I get "modified invalid". So far everything is great.
Finally I drag another file into the component and get two files. I can also see this in the model. But unfortunately the class attribute "modified valid" is not set.
Thanks again for any advice