[Edit] Solution thanks to @GH DevOps Make sure you are using rendermode InteractiveServer and use standard HTML tag for instead of
So I'm trying to bind a text input to a model generated by EF using scaffolding I have tried absolutely everything, read all the posts on here, copilot, and general web searches nothing works. some quick things I imagine people will suggest @bind-value with cap V, not supported in Blazor use Input instead, use @bind-Value:event="onchange" or @bind-Value:event="oninput", try @oninput="@(e => TempUser.Username = e.Value.ToString())" the list goes on. I was wondering if it was a browser incompatibility so I downloaded Chrome no luck. My Validation is basically saying there is no value in the text box. I have confirmed that my model is properly instantiated and I can manually add User Models to the db using EF. If I remove the validation I just get a post error saying it can't insert NULL fields into the db.
@page "/project"
@using ScrumTestApp.Components.Services
@using System.ComponentModel.DataAnnotations
@using System.Collections.Generic
@using Microsoft.EntityFrameworkCore
@using ScrumTestApp.Models
@using Microsoft.AspNetCore.Components.Forms
@using SystemTask = System.Threading.Tasks.Task;
@inject ProjectService ProjectService
@inject ScrumTestingContext DbContext
<PageTitle>Home</PageTitle>
<h1>Header</h1>
<EditForm Model="@TempUser" OnValidSubmit="@HandleSubmit" FormName="usersignup">
<DataAnnotationsValidator />
<ValidationSummary />
<div>
<label for="username">Enter UserName</label>
<InputText id="username" @bind-Value="TempUser.Username" @bind-Value:event="oninput" />
</div>
<div>
<label for="email">Enter Email</label>
<InputText id="email" @bind-Value="TempUser.Email" @bind-Value:event="oninput" />
</div>
<button type="submit">Submit</button>
</EditForm>
<a>@message</a>
<a>@TempUser.Username</a>
<a>@TempUser.Email</a>
@code {
private User TempUser { get; set; } = new User();
public string? message { get; set; }
//private UserPassword password1 = new UserPassword();
private async SystemTask HandleSubmit()
{
if (string.IsNullOrEmpty(TempUser.Email) || string.IsNullOrEmpty(TempUser.Username))
{
return;
}
DbContext.Users.Add(TempUser);
await DbContext.SaveChangesAsync();
TempUser = new();
message = $"User {TempUser.Username} submitted successfully!";
}
}
That's a snippet of the basic test page and here's the partial Model
public partial class User
{
public int UserId { get; set; }
[Required]
public string Email { get; set; }
[Required]
public string Username { get; set; }
public DateTime? JoinDate { get; set; }
public virtual ICollection<Comment> Comments { get; set; } = new List<Comment>();
public virtual ICollection<UserPassword> UserPasswords { get; set; } = new List<UserPassword>();
public virtual ICollection<Project> Projects { get; set; } = new List<Project>();
public virtual ICollection<Task> Tasks { get; set; } = new List<Task>();
}
Any help would be much appreciated I have also tried every way of formatting my Form with no luck, as far as copilot is concerned this should just work.
You are correct in that your use case of InputText
doesn't work. The problem is that the Razor compiler gets in a twist about how to handle @bind-Value:event="oninput"
.
However, that is easily corrected by creating an enhanced version of InputText
.
Here's mine. It also includes code to set the first focus.
@*
/// ============================================================
/// Author: Shaun Curtis, Cold Elm Coders
/// License: Use And Donate
/// If you use it, donate something to a charity somewhere
/// ============================================================
*@
@inherits InputText
@if (UpdateOnInput)
{
<input class="@this.CssClass"
type="text"
value="@this.CurrentValueAsString"
@oninput="this.OnChange"
@attributes=this.AdditionalAttributes
@ref=this.Element />
}
else
{
<input class="@this.CssClass"
type="text"
value="@this.CurrentValueAsString"
@onchange="this.OnChange"
@attributes=this.AdditionalAttributes
@ref=this.Element />
}
@code {
[Parameter] public bool UpdateOnInput { get; set; }
[Parameter] public bool SetFirstFocus { get; set; }
protected Task OnChange(ChangeEventArgs e)
{
this.CurrentValueAsString = e.Value?.ToString() ?? null;
return Task.CompletedTask;
}
protected async override Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender && this.SetFirstFocus && this.Element is not null)
await this.Element.Value.FocusAsync();
}
}
And another similar version:
@inherits InputText
<input class="@this.CssClass"
type="text"
value="@this.CurrentValueAsString"
@oninput="this.OnInput"
@onchange="this.OnChange"
@attributes=this.AdditionalAttributes
@ref=this.Element />
@code {
[Parameter] public bool UpdateOnInput { get; set; }
[Parameter] public bool SetFirstFocus { get; set; }
protected Task OnInput(ChangeEventArgs e)
{
if (this.UpdateOnInput)
this.CurrentValueAsString = e.Value?.ToString() ?? null;
return Task.CompletedTask;
}
protected Task OnChange(ChangeEventArgs e)
{
if (!this.UpdateOnInput)
this.CurrentValueAsString = e.Value?.ToString() ?? null;
return Task.CompletedTask;
}
protected async override Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender && this.SetFirstFocus && this.Element is not null)
await this.Element.Value.FocusAsync();
}
}
You can find the source code for adding the same functionality to the other InputBase
controls here: https://github.com/ShaunCurtis/Blazr.VSA/tree/master/Source/Libraries/Blazr.UI/Inputs