I am trying to trigger the model validation in Blazor by using EditForm.
For some reason, the oninput event doesn't seem to be called if using the InputText, but it works using a simple input element.
Have I missed something?
Here is an HTML sample:
<EditForm Model="#Model" OnValidSubmit="#OnValidSubmit" id="authorize">
<h1 class="mb-3">
<span class="d-block">Authorize</span>
</h1>
<DataAnnotationsValidator />
<div class="form-group">
<label class="sr-only" for="AuthorizeUsername">Username</label>
<div class="input-group mb-2">
<div class="input-group-prepend">
<div class="input-group-text"><i class="fas fa-user"></i></div>
</div>
<InputText type="text" class="form-control" id="AuthorizeUsername" placeholder="Username" #bind-value="#Model.Username" #bind-value:event="oninput" />
</div>
</div>
<div class="form-group">
<label class="sr-only" for="AuthorizePassword">Password</label>
<div class="input-group mb-2">
<div class="input-group-prepend">
<div class="input-group-text"><i class="fas fa-asterisk"></i></div>
</div>
<InputText type="password" class="form-control" id="AuthorizePassword" placeholder="Password" #bind-value="#Model.Password" #bind-value:event="oninput" />
</div>
</div>
<div class="form-group">
<ValidationSummary />
<button type="submit" class="btn btn-outline-primary"><i class="fas fa-sign-in-alt mr-1"></i> Login</button>
</div>
</EditForm>
If you need this for validation, see the answer for this:
How to make an EditForm Input that binds using oninput rather than onchange
Original Answer
TLDR: Blazor Input components do not support this out of the box. You need to roll your own by extending InputBase, and your Razor markup for your new component will put the input event binding directly on the input element.
It would be nice if this came as an out-of-the-box option, but at least there is a way to do it that isn't terrible. Be aware though that this quickly gets more complicated for more complicated input types. If you want your own InputBase<DateTime> derived class, for example, you need to be prepared to correctly handle DateTime formatting in the binding events.
The markup for your own version of InputText, lets call it MyInputTextCode that extends InputBase<string> would look something exactly like this:
#inherits MyInputTextCode;
<input type="text" id="#Id" class="#Class" #bind-value="CurrentValueAsString" #bind-value:event="oninput" />
where MyInputTextCode is the class name of your implementation of InputBase<string>
The usage would essentially be the same as InputText, but you would instead use the file name (witout the extension) of your .razor markup instead of InputText.
UPDATE 4-30-2020
I no longer recommend deriving from InputBase in your code-behind, instead you can simply #inherits an existing form component class such as InputText and override the markup in your .razor file. If this isn't clear please comment on this answer and I'll elaborate further in this update.
It works on a simple input because you are binding to the html attribute "value".
InputText is a C# class. The property name you need to bind to is Value with a capital V.
Change all #bind-value occurrences to #bind-Value and it should work.
As a workaround, I found that changing from Blazor components such as InputTextArea to plain HTML textarea tag and leveraging the binding on them can fix the problem:
<textarea #bind="#ViewModel.TargetProperty" #bind:event="oninput"/>
or for input tags:
<input type="email" #bind="#ViewModel.Email" #bind:event="oninput"/>
Works in .Net 5 Blazor WASM at least.
I found this answer and a workaround:
https://github.com/dotnet/aspnetcore/issues/12657
Basically #bind-Value:event="oninput" is not supported on <InputText> but you can easily derive a new control from 'InputText' which does update on input.
Quoted from the original github post for reference:
Create MyInputText.razor containing:
#inherits Microsoft.AspNetCore.Components.Forms.InputText
<input #attributes="#AdditionalAttributes" class="#CssClass" #bind="#CurrentValueAsString" #bind:event="oninput" />
Now when you use <MyInputText #bind-Value="#someval" /> it will behave just like InputText except it updates on each keystroke.
A similar technique as Amir Mahdi said in another answer, I just wanted to point out that this is explained on the official docs also now for Aspnetcore 6.0 and 7.0.
https://learn.microsoft.com/en-us/aspnet/core/blazor/forms-and-input-components?view=aspnetcore-6.0
See the heading 'InputText based on the input event'.
Here is how they suggest to use it, I however see the value of also being in charge of which client side event will trigger update (usually it will be 'oninput', but maybe you want to use another client side event?)
Just define a new reusable component like CustomInputText.razor with the following content :
#inherits InputText
<input #attributes="AdditionalAttributes"
class="#CssClass"
#bind="CurrentValueAsString"
#bind:event="#UpdateSourceTrigger" />
#code {
[Parameter]
public string UpdateSourceTrigger { get; set; } = "oninput";
}
To use it inside a razor view just use it like a regular InputText field, the only thing that is adjusted is that it automatically binds to the 'oninput' client side event. You can adjust which event also is bound to do an update. This can both be positive sine you see your changes on key stroke and negative in case updating the backend from the UI is slow, as every keyboard stroke will write data back to the bound property, possibly trigger additional processing too if you have bound it to an 'autosave' feature or similar.
I used the name UpdateSourceTrigger here for the property trigger event - as this reminds me a bit how we adjusted things in WPF when to write back to two way bound fields !
Another workaround for this issue would be to add a handler to #oninput and set the value to the model inside this handler:
<EditForm Model="Input">
<InputText #bind-Value="Input.Text" #oninput="HandleInputTextInput" />
</EditForm>
#{
private InputModel Input { get; } = new();
private void HandleInputTextInput(ChangeEventArgs e)
{
Input.Text = e.Value as string;
}
public class InputModel
{
public string? Text { get; set; }
}
}
This way you don't need to create a new component and can still use <InputText />.
Draw back of course is that this might bloat your code with handlers.
Related
I am trying to build a InputText for Blazor which holds a placeholder if the skill is yet null so is created as a new one, since I want to use the same razor component for edit and create new skill.
my code is
<div class="form-group">
<label>Skillname</label>
#if (Skill == null)
{
<InputText class="form-control" placeholder="Enter Skillname" #bind-Value="Skill.Name"/>
}
else
{
<InputText #bind-Value="Skill.Name" class="form-control"/>
}
</div>
I tried to set placeholder=.".." without having any effect. After research I found that they were using placeholder here even though it is not working for me.
I only found this possibility with telerik front end framework.
I was not able to find any reference to placeholder in the documentation.
Andy idea why placeholder is not working here or if there is any other workaround to achieve this?
There is no intellisense and that is what confuses people.
However, if you just use the placeholder attribute it will work.
<InputText id="lastName" class="form-control" placeholder="Last Name" #bind-Value="EmployeeVM.LastName"></InputText>
You're binding to #bind-Value="Skill.Name" so I'm assuming Skill isn't null. Your test is on skill, not skill.Name, so is never null you always hit the else option. Try:
#if (string.IsNullOrEmpty(skill.Name))
{
......
}
And you get:
However, you don't need to do any of this as the placeholder will only display when the field is empty.
Is there any way to disbale jquery validation on certain input fields inside a form? So that it won't bother me with the 'red text under my input' or whenever I submit my form. I'm searching for a while now but without any succes. I tried using formnovalidate="formnovalidate" from this questions but also without any succes.
Here's my cshtml input code:
<div class="form-group">
<label asp-for="preExposure" class="control-label"></label>
<input asp-for="preExposure" id="preExposureInput" class="form-control" type="text"/>
<span asp-validation-for="preExposure" class="text-danger"></span>
</div>
Although I posted as a comment that it was pretty similar to the linked question, the most important part of that answer is below:
Once you have the jquery validation turned on for the form with the .validate() you can still configure the rules for the individual element that you want, and remove all the rules.
$('#myfield').rules('remove'); // removes all rules for this field
I'm checking out Asp.Net Core on .Net core. Scaffolding has created some templates. The default validation for the model is not sufficient, so I've added some extra validation when the object is send to the controller
ViewData.ModelState.AddModelError(nameof(Invoice.InvoiceNr), "Invoice number should be unique.");
Now in the browser I only see that message when #Html.ValidationMessage("InvoiceNr") is added to the cshtml file. Only asp-validation-for="InvoiceNr" does not seem to present any property errors.
It took some time before I figured this out. Can someone shed some light on this why this is, it seems counter-intuitive to me, to have to add 2 lines to show all validation errors.
Thanks!
#Shyju
<div class="form-group">
<label asp-for="InvoiceNr" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="InvoiceNr" class="form-control"/>
<span asp-validation-for="InvoiceNr" class="text-danger" />
</div>
</div>
#GSerg
The reason it is not working is because you are not using the validation-for tag helper correctly. Instead of using the self closing notation, you should use an explicit closing for the span.
Replace
<span asp-validation-for="InvoiceNr" class="text-danger" />
With
<span asp-validation-for="InvoiceNr" class="text-danger"></span>
In short, you do not need to use both the tag helper and the html helper together to the the validation error. With the correct usage of tag helper, you will be able to see the validation error message.
In a Razor view I have input type="text", a hidden field and a button. I can access hidden field from Form collection but its weird I cant access input type="text" value inside my action. I am not sure if my understanding is correct or not but I was thinking as all fields inside form should be available inside action.
Below is my code please:
#using (Html.BeginForm())
{
<div style="margin-top: 40px;">
<input id="txtDateFrom" class="span2" size="16" value="#Model.StartDate.ToString("dd/MM/yyyy") " readonly="readonly" type="text">
#Html.Hidden("currencyCode", (object)ViewBag.currencyCode)
</div>
<button onclick="#Url.Action("ExchangeRateDetails", "ExchangeRate")" class="btn btn-lg span2 ARML50px">
}
I highly appreciate your time, guidance and help.
The reason your hidden input works is that you render this with help from the Html helper #Html.Hidden. This helper render the input field with the name attribute.
Your <input type="text"> is missing the name attribute. So try writing like this:
<input id="txtDateFrom" name="txtDateFrom" class="span2" size="16" value="#Model.StartDate.ToString("dd/MM/yyyy") " readonly="readonly" type="text" />
The name="txtDateFrom" will make the value appear in your FormCollection.
Try this way
You don't need onclick="#Url.Action("ExchangeRateDetails", "ExchangeRate")" to the button
Change your button for below way
<button type="submit" class="btn btn-lg span2 ARML50px">
And Now your controller can get the input text
[HttpPost]
Public ActionResult ExchangeRateDetails(YourmodelClass xxx)
{
string dates=Model.StartDate;
}
This website have lot and lot of answers for how to send a model values from view to controllers by see the Related discussion on this page right corner .
How does one set the label of a checkbox? I looked at some sites and they are using lambda expressions, but I can't understand them. I am new to asp.net MVC.
#{
bool chkVal = false;
}
<li>#Html.CheckBox("chksumma",chkVal,new {#value = "5"})</li>
<li>#Html.LabelFor(, "");
This is a really good way:
<div class="checkbox">
<label>#Html.CheckBoxFor(x => item.IsSelected) #Html.DisplayNameFor(x => item.IsSelected)</label>
</div>
It's what is recommended by bootstrap 3.
It works in a table.
You can click on the check box OR the label to select the box. (This is an important usability feature.)
The cursor is properly the "hand" instead of the arrow pointer.
EDIT
This is really easy to do in Bootstrap 4.
You just wrap your label and input inside form-check markup:
<div class="form-check">
<input class="form-check-input" type="checkbox" value="" id="defaultCheck1">
<label class="form-check-label" for="defaultCheck1">Default checkbox</label>
</div>
If you are using a Model you could do:
<li>#Html.CheckBoxFor(f=> f.chksumma)</li>
<li>#Html.LabelFor(f=> f.chksumma)</li>
Then use the attributes TGH pointed out
otherwise if you don't have a model all you can do for labels is:
#Html.Label("LabelText")
which prints a standalone label
or and craft it if you want it to link with the item
<label for="chksumma">LAbelText</label>
If you really don't want to hand craft it you can write your own HTML helper as explained here
http://develoq.net/2011/how-to-create-custom-html-helpers-for-asp-net-mvc-3-and-razor-view-engine/
I'm assuming that you want the label to tick the checkbox when you click on it.
In this case, the for attribute of the HTML <label> field must point to the ID of the relevant input element.
If you're using a model, #Html.CheckBoxFor will generate a checkbox without an ID, so you will need to add an ID to the checkbox, then point your label to the same ID. The easiest way is to replicate the checkbox's name into its ID field using the #Html.NameFor helper method. Here's an example:
#Html.CheckBoxFor(x => x.Active, new {id=Html.NameFor(x => x.Active)})
<label for="#Html.NameFor(x => x.Active)">Active</label>
Generated HTML (without validation attributes):
<input id="[0].Active" name="[0].Active" type="checkbox" value="true" />
<input name="[0].Active" type="hidden" value="false" />
<label for="[0].Active">Active</label>
I worked on something similar and got around it by this snipped code
<div class="row">
<div class="col-xs-3">
<label>
#Html.CheckBoxFor(x => x.AdvanceSearch.IsExactPhrase)
#Html.LabelFor(x => x.AdvanceSearch.IsExactPhrase)
</label>
</div> ...
Hope it helps the others
You shouldn't need the <label> tag at all:
<div class="block mTop20">
#HtmlCheckboxFor(f => f.prop)
#Html.LabelFor(f=>f.prop,"This is the label text")
</div>