how to get the value of a radio button in blazor? - c#

hello community I have a problem how can I get the value of a radio button in blazor, I have three radio buttons in the first two I want to put a value number 0 and 16 to save them in the database and in the third button a bool value to show some input if that value was selected,but the truth is I don't know how to do this since I understand that in blazor you can't even put the bidirectional values with bind-value
this is my code:
<div class="form-group col-md-2">
<label>Impuestos</label>
<div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="inlineRadioOptions" id="inlineRadio1" #bind-value="#ImpuestoDetalle.Tasa">
<label class="form-check-label" for="inlineRadio1">0%</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="inlineRadioOptions" id="inlineRadio2" #bind-value="#ImpuestoDetalle.Tasa">
<label class="form-check-label" for="inlineRadio2">16%</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="inlineRadioOptions" id="inlineRadio3" #bind="#Perzonalizado">
<label class="form-check-label" for="inlineRadio3">Perzonalizado</label>
</div>
</div>
</div>
#if (Perzonalizado)
{
<div class="form-group col-md-2">
<label>Tasa</label>
<div>
<input type="number" class="form-control" #bind-value="#ImpuestoDetalle.Tasa" />
</div>
</div>
}
#code {
private Impuesto Impuesto = new Impuesto();
private ImpuestoDetalle ImpuestoDetalle = new ImpuestoDetalle();
private Boolean Perzonalizado = false;
}

Tried this really quickly and achieved in a slightly different way using onchange event:
<div class="form-group col-md-2">
<label>Impuestos</label>
<div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="inlineRadioOptions" id="inlineRadio1" #onchange="#(() => UpdatePercentage(0))">
<label class="form-check-label" for="inlineRadio1">0%</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="inlineRadioOptions" id="inlineRadio2" #onchange="#(() => UpdatePercentage(16))">
<label class="form-check-label" for="inlineRadio2">16%</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="inlineRadioOptions" id="inlineRadio3" #onchange="#(() => Perzonalized())">
<label class="form-check-label" for="inlineRadio3">Perzonalizado</label>
</div>
</div>
</div>
#if (Perzonalizado)
{
<div class="form-group col-md-2">
<label>Tasa</label>
<div>
<input type="number" class="form-control" #bind-value="#ImpuestoDetalleM.Tasa" />
</div>
</div>
}
#code {
public ImpuestoDetalle ImpuestoDetalleM = new ImpuestoDetalle();
private Boolean Perzonalizado = false;
public class ImpuestoDetalle
{
public int Tasa { get; set; }
}
public void Perzonalized()
{
Perzonalizado = true;
}
public void UpdatePercentage(int percentage)
{
Perzonalizado = false;
ImpuestoDetalleM.Tasa = percentage;
}
}
So basically when the radio button is clicked, we fill the value by passing from parameter.
You can also try the snippet here: https://blazorrepl.com/repl/ckOBGDvj26S1LtXe41

Related

Create a Condition For all non empty fields to be ReandOnly - ASP.NET Core 6.0 MVC

I am developing my first web application with ASP.NET Core 6, and I have a form that shows some fields that I already have information inside of my database.
The problem is: these fields needs to be read-only, because my user needs to considerate the information from my database. If is null, then he needs to insert a value.
Here is an example (consider the field with already set readonly). Most of fields will need this code:
<div class="form-group row">
<div class="col-3">
<label for="Renda Bruta">Associado Desde:</label>
<input type="text" class="form-control">
</div>
<div class="col-3">
<label for="Renda Liquida">Cota Capital</label>
<input type="text" class="form-control">
</div>
<div class="col-6" style="text-align:center">
<label for="ServidorPublico">IAP:</label>
<div class="input-group mb-3">
<input type="text" class="form-control" placeholder="Quantidade" value="#Html.DisplayFor(model => model.iAP.QuantidadeProduto)" ReadOnly="readonly"/>
<input type="text" class="form-control" placeholder="Produtos" value=""#Html.DisplayFor(model => model.iAP.Pro)" ReadOnly="readonly"/>
</div>
</div>
</div>
<div class="form-group row">
<div class="col-4">
<label for="Renda Bruta">Margem Contribuição</label>
<input type="text" class="form-control">
</div>
<div class="col-8" style="text-align:center">
<label for="ServidorPublico">Cheque Especial</label>
<div class="input-group mb-3">
<input type="text" class="form-control" placeholder="Dias de Utilização" />
<input type="text" class="form-control" placeholder="Valor Utilizado" />
<input type="text" class="form-control" placeholder="Valor Contratado" />
</div>
</div>
</div>
I already build the form, and put some fields readonly with ReadOnly="readonly", but is there a way to loop all fields and put readonly with a loop or I really need to write in all fields the code `ReadOnly="readonly" ? My form is really big
But is there a way to loop all fields and put readonly with a loop or
I really need to write in all fields the code `ReadOnly="readonly" ?
My form is really big
Yes, you can set that ReadOnly attribute based on the value of your textbox field.
In this scenario you have to consider two way, either you should consider your textbox name attribute or type="text" attribute. Upon these two very way we will be decided which textbox set to readonly which is not.
For [type='text'] Attribute:
When [type='text'] means we will check all the textbox type of text and check if the textbox have value and set the readonly attribute:
View:
<div class="form-group row">
<div class="col-3">
<label for="Renda Bruta">Associado Desde:</label>
<input type="text" name="Associado" class="form-control">
</div>
<div class="col-3">
<label for="Renda Liquida">Cota Capital</label>
<input type="text" name="Cota" class="form-control">
</div>
<div class="col-6" style="text-align:center">
<label for="ServidorPublico">IAP:</label>
<div class="input-group mb-3">
<input type="text" name="Quantidade" class="form-control" placeholder="Quantidade" value="Test Value" />
<input type="text" name="Produtos" class="form-control" placeholder="Produtos" value="Test Value Products" />
</div>
</div>
</div>
<div class="form-group row">
<div class="col-4">
<label for="Renda Bruta">Margem Contribuição</label>
<input type="text" name="Margem" class="form-control">
</div>
<div class="col-8" style="text-align:center">
<label for="ServidorPublico">Cheque Especial</label>
<div class="input-group mb-3">
<input type="text" name="Dias" class="form-control" placeholder="Dias de Utilização" />
<input type="text" name="Utili" class="form-control" placeholder="Valor Utilizado" />
<input type="text" name="Contra" class="form-control" placeholder="Valor Contratado" />
</div>
</div>
</div>
Script:
#section scripts {
<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.2.1.min.js"></script>
<script src="https://cdn.datatables.net/1.11.3/js/jquery.dataTables.min.js"></script>
<script>
$(document).ready(function () {
$("input[type='text']").each(function (index, item) {
console.log(item);
if ($(item).val() != "") {
$(item).attr('readonly', true);
}
});
});
</script>
}
Note: When will will set readonly to a textbox which has value based on the text type then we have to consider like input[type='text']
For name Attribute:
#section scripts {
<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.2.1.min.js"></script>
<script src="https://cdn.datatables.net/1.11.3/js/jquery.dataTables.min.js"></script>
<script>
$(document).ready(function () {
$("input").each(function (index, item) {
console.log(item);
if ($(item).val() != "") {
$(item).attr('readonly', true);
}
});
});
</script>
}
Note: Remember in this scenario, you need to set name property for your textbox to identify uniquely as you can see I have added name property
Output:
what I understand that you want to make the input field enterable when the value of it is null. this is done by javascript.
I suggest to make all input fields read only.
use javascript to test each field, if its value is null make it enterable.
for example:
<input type="text" id="text1" class="form-control" placeholder="Quantidade" value="#Html.DisplayFor(model => model.iAP.QuantidadeProduto)" ReadOnly="readonly"/>
<script>
window.onload = function() {
if (document.getElementById("text1").value.length == 0)
{
document.getElementById("text1").readOnly = false;
}}
</script>
so basically when the page is loading the script will check if the input is null or not and it will do the action.

Asp.net core Razor Radio button not passing desired values to controller

I have a problem with my form its not passing radio button selected value to controller but another values are passed successfully when debugging.
Please note Job.PublicSubmissionReviewed its boolean, I noticed the this Job.PublicSubmissionReviewed passed through the form at all.
What am I missing on the radio button:
Here is my form and controller, your assistance will be greatly appreciated:
<form asp-action="Review">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="Job.Id" />
<div class="form-group">
<p><strong>Approve or Reject public submission</strong></p>
<div class="form-group form-check-inline">
<label class="form-check-label">
<input class="form-radio-input" name="status" value="True" type="radio" asp-for="Job.PublicSubmissionReviewed" /> Approve
</label>
</div>
<div class="form-group form-check-inline">
<label class="form-check-label">
<input class="form-check-input" name="status" value="False" type="radio" asp-for="Job.PublicSubmissionReviewed" /> Reject
</label>
</div>
</div>
<div class="form-row showapprove" id="True">
<div class="form-group col-md-6">
<label asp-for="Job.JobCategoryId" class="control-label"></label>
<select asp-for="Job.JobCategoryId" class="form-control" asp-items="ViewBag.JobCategoryId">
</select>
</div>
<div class="form-group col-md-6">
<label asp-for="Job.Name" class="control-label"></label>
<input asp-for="Job.Name" class="form-control" />
<span asp-validation-for="Job.Name" class="text-danger"></span>
</div>
<div class="form-group col-md-6">
<label asp-for="Job.JobNo" class="control-label"></label>
<input asp-for="Job.JobNo" class="form-control" />
<span asp-validation-for="Job.JobNo" class="text-danger"></span>
</div>
<div class="form-group col-md-6">
<label asp-for="Job.ContractorId" class="control-label"></label>
<select asp-for="Job.ContractorId" class="form-control" asp-items="ViewBag.ContractorId">
</select>
</div>
</div>
<div class="form-group">
<button type="submit" class="btn btn-outline-primary"><i class="fas fa-save" aria-hidden="true"></i> Submit</button>
</div>
</form>
public async Task<IActionResult> Review(int id, JobViewModel model)
{
if (id != model.Job.Id)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
var job = _context.Jobs.Where(j => j.Id == id).SingleOrDefault();
if (model.Job.PublicSubmissionReviewed == true) // approve public submission
{
job.PublicSubmissionReviewed = true;
job.PublicSubmissionReviewDate = DateTime.Now;
job.Name = model.Job.Name;
job.New = true;
job.JobNo = model.Job.JobNo;
job.JobCategoryId = model.Job.JobCategoryId;
job.ContractorId = model.Job.ContractorId;
_context.Update(job);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Public));
}
else if (model.Job.PublicSubmissionReviewed == false) // reject public submission
{
job.PublicSubmissionReviewed = true;
job.PublicSubmissionReviewDate = DateTime.Now;
job.New = false;
job.PublicSubmissionRejected = true;
job.PublicSubmissionRejectedDate = DateTime.Now;
job.PublicSubmissionReviewRejectReason = model.Job.PublicSubmissionReviewRejectReason;
_context.Update(job);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Public));
}
}
catch (DbUpdateConcurrencyException)
{
if (!JobExists(model.Job.Id))
{
return NotFound();
}
else
{
throw;
}
}
}
return View(model);
}
The name HTML attribute in a form element is what will be sent to the server to identify that field once you submit the form. Razor's model binding expects a certain name for form fields, and asp-for automatically sets that name for you. Since you've manually specified a name instead, the model binder will not be able to recognize the field, and therefore will not set it in your model.
It looks like you're setting the name in order to group the radio buttons together. Since asp-for will use the same name for a given bound property, you do not need to worry about that; all radio buttons corresponding to a certain property will be grouped together.
Therefore, you can simply remove the name attribute and your code should then work fine:
<input class="form-radio-input" value="True" type="radio" asp-for="Job.PublicSubmissionReviewed" /> Approve
<input class="form-check-input" value="False" type="radio" asp-for="Job.PublicSubmissionReviewed" /> Reject

Binding generic value back to controller via post method

I can't figure out how to bind back generic value from view when sending it back to controller via post method.
I have generic class PageModel that inherites from GenericModel. PageModel has additional parameter Page (class that have two int parameters, pageSize and pageNumber). GenericModel has only generic value of T named viewModel and nothing more. The problem is that standard C# binder binds Page parameter without any issues, but no matter what I'm trying to do ViewModel is never filled in.
Models:
public class GenericModel<T>
{
public T ViewModel { get; set; }
public GenericModel(T viewModel)
{
ViewModel = viewModel;
}
public GenericModel()
{
}
}
public class PageModel<T> : GenericModel<T>
{
public Page Page { get; set; }
public PageModel(T viewModel, Page page) : base(viewModel)
{
Page = page;
}
public PageModel() : base()
{
}
}
Generic Parameter:
public class UserModel
{
public string Id { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public string ConfirmPassword { get; set; }
public IList<string> Roles { get; set; }
public IList<string> NewRoles { get; set; }
}
Controller method
[HttpPost]
public async Task<IActionResult> Update(PageModel<UserModel> model)
{
var isUpdated = await _userServices.Update(model.ViewModel);
ViewData["IsUpdated"] = isUpdated;
return View("Index", await _userServices.GetUsersPage(model.Page.PageNumber, model.Page.PageSize));
}
View:
#model PageModel<UserModel>
#{
ViewData["Title"] = "Update";
}
<h1>Update</h1>
<form asp-controller="Admin" asp-action="Update" method="post">
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group">
<label asp-for="ViewModel.Id"></label>
<input type="text" asp-for="ViewModel.Id" disabled="disabled" class="form-control" />
<span asp-validation-for="ViewModel.Id" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="ViewModel.Password"></label>
<input type="password" asp-for="ViewModel.Password" class="form-control" />
<span asp-validation-for="ViewModel.Password" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="ViewModel.ConfirmPassword"></label>
<input type="password" asp-for="ViewModel.ConfirmPassword" class="form-control" />
<span asp-validation-for="ViewModel.ConfirmPassword" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="ViewModel.Roles"></label>
<input type="text" asp-for="ViewModel.Roles" class="form-control" hidden="hidden" />
<span asp-validation-for="ViewModel.Roles" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Page.PageNumber"></label>
<input type="number" asp-for="Page.PageNumber" class="form-control" hidden="hidden" />
<span asp-validation-for="Page.PageNumber" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Page.PageSize"></label>
<input type="number" asp-for="Page.PageSize" class="form-control" hidden="hidden" />
<span asp-validation-for="Page.PageSize" class="text-danger"></span>
</div>
#foreach (var availableRole in (IList<IdentityRole>)ViewData["AllRoles"])
{
<div class="form-check">
<input class="form-check-input" type="checkbox" name="newRoles" value="#availableRole.Name"
checked="#Model.ViewModel.Roles.Contains(availableRole.Name)">
<label class="form-check-label">#availableRole</label>
</div>
}
<button type="submit" class="btn btn-success">Change</button>
Do you know what can be the issue? Is naming convention wrong? I've already tried to find answer on stack, but with no luck.
**
EDIT 1:
**
This is what is generated by ASP.NET (Copied from google chrome)
<form method="post" action="/Admin/Update/439c61f5-d721-4e10-b49c-6263b7929c6a">
<div class="text-danger validation-summary-valid" data-valmsg-summary="true"><ul><li style="display:none"></li>
</ul></div>
<div class="form-group">
<label asp-for="ViewModel.Id"></label>
<input type="text" asp-for="ViewModel.Id" disabled="disabled" class="form-control" />
</div>
<div class="form-group">
<label for="ViewModel_Password">Password</label>
<input type="password" class="form-control" data-val="true" data-val-length="The Password must be at least 6 and at max 100 characters long." data-val-length-max="100" data-val-length-min="6" id="ViewModel_Password" name="ViewModel.Password">
<span class="text-danger field-validation-valid" data-valmsg-for="ViewModel.Password" data-valmsg-replace="true"></span>
</div>
<div class="form-group">
<label for="ViewModel_ConfirmPassword">Confirm password</label>
<input type="password" class="form-control" data-val="true" data-val-equalto="The password and confirmation password do not match." data-val-equalto-other="*.Password" id="ViewModel_ConfirmPassword" name="ViewModel.ConfirmPassword">
<span class="text-danger field-validation-valid" data-valmsg-for="ViewModel.ConfirmPassword" data-valmsg-replace="true"></span>
</div>
<div class="form-group">
<label for="ViewModel_Roles">Roles</label>
<input type="text" class="form-control" hidden="hidden" id="ViewModel_Roles" name="ViewModel.Roles" value="System.Collections.Generic.List`1[System.String]">
<span class="text-danger field-validation-valid" data-valmsg-for="ViewModel.Roles" data-valmsg-replace="true"></span>
</div>
<div class="form-group">
<label for="Page_PageNumber">PageNumber</label>
<input type="number" class="form-control" hidden="hidden" data-val="true" data-val-required="The PageNumber field is required." id="Page_PageNumber" name="Page.PageNumber" value="1">
<span class="text-danger field-validation-valid" data-valmsg-for="Page.PageNumber" data-valmsg-replace="true"></span>
</div>
<div class="form-group">
<label for="Page_PageSize">PageSize</label>
<input type="number" class="form-control" hidden="hidden" data-val="true" data-val-required="The PageSize field is required." id="Page_PageSize" name="Page.PageSize" value="5">
<span class="text-danger field-validation-valid" data-valmsg-for="Page.PageSize" data-valmsg-replace="true"></span>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" name="newRoles" value="Administrator">
<label class="form-check-label">Administrator</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" name="newRoles" value="User" checked="checked">
<label class="form-check-label">User</label>
</div>
<button type="submit" class="btn btn-success">Change</button>
<input name="__RequestVerificationToken" type="hidden" value="CfDJ8Hsh_QOxexZLjyWnCjnNzz2ZhIuA-aPvi2MKBsCF12vrc6FY2yJnWGo1Nq9xNtwuiq7dTKdt93hUTJUf0PDD8RX1CJGgo0Jc3eDJMf8Ymh13fz0K60_S-uajXL3lNZalJJ58idjvok61tqa6oddepoWN1A0BUYHsk-h-PdfUCswqBSrt9GsHdbRvS5NrIitiZQ"></form>
Form data from google dev tools:
ViewModel.Password:
ViewModel.ConfirmPassword:
ViewModel.Roles: System.Collections.Generic.List%601%5BSystem.String%5D
Page.PageNumber: 1
Page.PageSize: 5
newRoles: User
__RequestVerificationToken: CfDJ8Hsh_QOxexZLjyWnCjnNzz2AyLo8vWEn4NIFS4brVjbJsYdFKgY97yj5IO8trooYDKkrdxPlFrGk2hmPQrmoEKgmGSno2jdOwGud-5Fcy8ewmp7K2pl1XODyKXxYSaZ3TngHSl1KLpMb9REpq4_Nqh45sdO1eBaMqpw3dfgCoAbvc6m2nEKJlDaRm_2eaKTX-w
Decoded form (the same as above):
ViewModel.Password=&ViewModel.ConfirmPassword=&ViewModel.Roles=System.Collections.Generic.List%601%5BSystem.String%5D&Page.PageNumber=1&Page.PageSize=5&newRoles=User&__RequestVerificationToken=CfDJ8Hsh_QOxexZLjyWnCjnNzz2AyLo8vWEn4NIFS4brVjbJsYdFKgY97yj5IO8trooYDKkrdxPlFrGk2hmPQrmoEKgmGSno2jdOwGud-5Fcy8ewmp7K2pl1XODyKXxYSaZ3TngHSl1KLpMb9REpq4_Nqh45sdO1eBaMqpw3dfgCoAbvc6m2nEKJlDaRm_2eaKTX-w
EDIT 2
I've changed the disable tag from id to readonly, and now ID is being sent. I don't thing I've changed anything else but I think thanks to that every single other property is added, but IList with roles. There still is a problem. Roles don't bind at all.
ViewModel.Id: fde0b182-3b24-4d5b-b31e-3680b7cfd4de
ViewModel.Password: 19923845379
ViewModel.ConfirmPassword: 1284326898838
ViewModel.Roles: System.Collections.Generic.List`1[System.String]
Page.PageNumber: 1
Page.PageSize: 5
newRoles: Administrator
newRoles: User
__RequestVerificationToken: CfDJ8Hsh_QOxexZLjyWnCjnNzz1Hy5YNNny4vPyGFd434Uybuo-O-dMFHT7eSKvd7JKA_dqxlQDIFlNzVsSjTDT6lzl7d2AU6Pj1nVRUyux3OZ2cGbyyBVKZHUI0Kq4u_MAx_b_29SUVSYh5Tpayc-0WPdcjGfxKLvL1qrbn6qeHcNk356VsPG1AC5cphft3frjILA
EDIT 3 [Solved]
Thanks to #itminus help I could solve the issue. Below you have changed form with two versions of the same - Roles with
<form asp-controller="Admin" asp-action="Update" method="post">
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group">
<label asp-for="ViewModel.Id"></label>
<input type="text" asp-for="ViewModel.Id" readonly class="form-control" />
<span asp-validation-for="ViewModel.Id" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="ViewModel.Password"></label>
<input type="password" asp-for="ViewModel.Password" class="form-control" />
<span asp-validation-for="ViewModel.Password" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="ViewModel.ConfirmPassword"></label>
<input type="password" asp-for="ViewModel.ConfirmPassword" class="form-control" />
<span asp-validation-for="ViewModel.ConfirmPassword" class="text-danger"></span>
</div>
#for(int i = 0; i < Model.ViewModel.Roles.Count(); i++) {
<div class="form-group">
<label asp-for="ViewModel.Roles[i]"></label>
<input type="text" asp-for="ViewModel.Roles[i]" class="form-control" hidden="hidden" />
<span asp-validation-for="ViewModel.Roles[i]" class="text-danger"></span>
</div>
}
<div class="form-group">
<input type="number" asp-for="Page.PageNumber" class="form-control" hidden="hidden" />
<span asp-validation-for="Page.PageNumber" class="text-danger"></span>
</div>
<div class="form-group">
<input type="number" asp-for="Page.PageSize" class="form-control" hidden="hidden" />
<span asp-validation-for="Page.PageSize" class="text-danger"></span>
</div>
#foreach (var availableRole in (IList<IdentityRole>)ViewData["AllRoles"])
{
<div class="form-check">
<input class="form-check-input" type="checkbox" name="ViewModel.NewRoles[]" value="#availableRole.Name"
checked="#Model.ViewModel.Roles.Contains(availableRole.Name)">
<label class="form-check-label">#availableRole</label>
</div>
}
<button type="submit" class="btn btn-success">Change</button>
</form>
What is being sent from form now. (Example values)
ViewModel.Id: bf872461-f429-497f-8159-898e1dfafad9
ViewModel.Password: 1394657234609243070
ViewModel.ConfirmPassword: 2346-7345-67356667
ViewModel.Roles[0]: User
Page.PageNumber: 1
Page.PageSize: 5
ViewModel.NewRoles[]: Administrator
ViewModel.NewRoles[]: User
__RequestVerificationToken: CfDJ8Hsh_QOxexZLjyWnCjnNzz1AvzPUt8DrSfqpOni-Q65jAFnRqNs875teRTned_OQ6S7GV19WwWRqE7yRgTNmeeX9Twg4RjgQR_JEibtFYpHN6zbDJgLeauyyHxwOukRSTl0GZIRii5VaQBUxIbK6A8qHxgl4bn5-01YLj8bOXV9Ze7TvdP3MTX7ghYcAprPUJQ
Is naming convention wrong?
Yes. The name convention is :
Dot (.) represents property
[] represents collection index or dictionary
However, in your previous code, NewRoles fields have the name of newRoles:
<input ... name="newRoles" ...>
which is not correct. The same goes for the Roles property.
So you need change you code in following way:
Roles:
<label asp-for="ViewModel.Roles"></label>
<input type="text" asp-for="ViewModel.Roles" class="form-control" hidden="hidden" />
<span asp-validation-for="ViewModel.Roles" class="text-danger"></span>
#for(var i=0; i < Model.ViewModel.Roles.Count(); i++)
{
<input type="hidden" name="ViewModel.Roles[]" value="#Model.ViewModel.Roles[i]" />
}
NewRoles:
#foreach (var availableRole in (IList<IdentityRole>)ViewData["AllRoles"])
{
<div class="form-check">
<input class="form-check-input" type="checkbox"
name="ViewModel.NewRoles[]"
value="#availableRole.Name"
checked="#Model.ViewModel.Roles.Contains(availableRole.Name)">
<label class="form-check-label">#availableRole</label>
</div>
}

Automatically refresh a component in Blazor

I am working on a Blazor page for adding a new object. The object "RepairOrder" has List of object "RepairSection".
On the page there is an area that will loop through the List "RepairOrder"."RepairSections" and show the elements:
<div class="col-lg-10">
#if (sections.Count > 0)
{
foreach (var sec in sections)
{
<h3>Section #sec.SectionNumber</h3>
<div class="row">
<div class="col-lg-1"></div>
<div class="col-lg-5">
<label for="Failure" class="control-label">Failure: </label>
<input for="Failure" class="form-control" bind="#sec.Failure" readonly />
</div>
<div class="col-lg-1"></div>
<div class="col-lg-1">
<label><input type="checkbox" checked="#IsCApprovedChecked(sec)" /> Warranty</label>
</div>
<div class="col-lg-2">
<label><input type="checkbox" value="#IsWarrantyChecked(sec)" /> Repair Approved</label>
</div>
</div>
<div class="row">
<div class="col-lg-1"></div>
<div class="col-lg-10">
<label for="AdminComments" class="control-label">Admin Comments: </label>
<input for="AdminComments" class="form-control" bind="#sec.AdminComments" readonly />
</div>
</div>
<div class="row">
<div class="col-lg-1"></div>
<div class="col-lg-10">
<label for="TechComments" class="control-label">Tech Comments: </label>
<input for="TechComments" class="form-control" bind="#sec.TechComments" readonly />
</div>
</div>
}
}
</div>
After all the current sections in the list have been added to the page, there is a button to add a new section. When the button is clicked, the function changes a bool value to true to open a modal as a dialog. The modal contains fields to input a new section elements.
function called to open the modal:
protected void AddSectionCalled()
{
_newSection = new RepairSection();
this.isAddNew = true;
}
Modal Code:
<div class="modal" tabindex="-1" style="display:block" role="dialog">
<div class="modal-dialog modal-dialog-scrollable modal-xl">
<div class="modal-content">
<div class="modal-header">
<h3 class="modal-title">New Repair Section</h3>
<button type="button" class="close" onclick="#CloseModal"><span aria-hidden="true">X</span></button>
</div>
<div class="modal-body">
<form>
<div class="row">
<div class="col-lg-1"></div>
<div class="col-lg-2">
<label for="sectionLetter" class="control-label">Section: </label>
<input for="sectionLetter" class="form-control" bind="#_newSection.SectionNumber" />
</div>
<div class="col-lg-1"></div>
<div class="col-lg-2">
<label><input type="checkbox" bind="#_newSection.Warranty" /> Warranty</label>
</div>
<div class="col-lg-2">
<label><input type="checkbox" bind="#_newSection.CustomerApproved" /> Repair Approved</label>
</div>
</div>
<div class="row">
<div class="col-lg-1"></div>
<div class="col-lg-10">
<label for="_failure" class="control-label">Failure: </label>
<input for="_failure" class="form-control" bind="#_newSection.Failure"/>
</div>
</div>
<div class="row">
<div class="col-lg-1"></div>
<div class="col-lg-10">
<label for="_adminComments" class="control-label">Admin Comments: </label>
<input for="_adminComments" class="form-control" bind="#_newSection.AdminComments" />
</div>
</div>
<div class="row">
<div class="col-lg-1"></div>
<div class="col-lg-10">
<label for="_techComments" class="control-label">Tech Comments: </label>
<input for="_techComments" class="form-control" bind="#_newSection.TechComments"/>
</div>
</div>
<br/>
<button class="btn btn-primary float-left" onclick="AddNewSection">Add New Section</button>
</form>
</div>
</div>
</div>
</div>
When the "Add New Section" button is clicked, the "_newSection" object created from the information collected in the modal is added to the "sections" list that was originally looped through when the page was loaded.
private void AddNewSection()
{
sections.Add(_newSection);
this.StateHasChanged();
this.isAddNew = false;
}
as you can see I added the "StateHasChanged()" after the new section is added to the sections list. However the page does not render to display the new section.
I originally had created dummy data on the page "OnInitAsync()" event that loaded the sections list with data before it was displayed. This way I could make sure the page displayed what was in the list correctly.
How can I make the page re-render the information in the list after user adds a new object to the list?
----Edit-----
Below is the code for the entire page. I will try and minimize this on the weekend, however there really is not a lot here.
#page "/AddRepairOrder"
#using ShopLiveWebVersion2._0.Models
#using ShopLiveWebVersion2._0.DataAccess
#using ShopLiveWebVersion2._0.Services
#using ShopLiveWebVersion2._0.Data
#inject IUriHelper UriHelper
#inject RepairOrderContext context
<div class="row">
<div class="col-lg-1"></div>
<div class="col-lg-10"><h1>Create New Repair Order</h1></div>
</div>
<br /><br />
<form id="AddROForm">
<div class="form-group">
<div class="row">
<div class="col-lg-1"></div>
<div class="col-lg-2">
<label for="ControlNumber" class="control-label">Repair Order #: </label>
<input for="ControlNumber" class="form-control" bind="#ro.ControlNumber" maxlength="15" required />
</div>
<div class="col-lg-1">
<label for="TagNumber" class="control-label">Tag #: </label>
<input for="TagNumber" class="form-control" bind="#ro.TagNumber" maxlength="8" />
</div>
<div class="col-lg-3">
<label for="VIN" class="control-label">VIN: </label>
<input for="VIN" class="form-control" bind="#ro.VIN" maxlength="18" />
#*<small id="Chasis" class="form-text text-muted">#ro.GetChassisNumber()</small> figure out how to get chassis from vin after box looses focus*#
</div>
<div class="col-lg-2">
<label for="Make" class="control-label">Make: </label>
<input for="Make" class="form-control" bind="#ro.Make" maxlength="30" />
</div>
<div class="col-lg-2">
<label for="Madel" class="control-label">Model: </label>
<input for="Madel" class="form-control" bind="#ro.Madel" maxlength="30" />
</div>
</div>
<div class="row AddRow">
<div class="col-lg-1"></div>
<div class="col-lg-4">
<label for="Customer" class="control-label">Customer: </label>
<input for="Custoemr" class="form-control" bind="#ro.Customer" maxlength="50" />
</div>
<div class="col-lg-2">
<label asp-for="Location" class="control-label">Vehicle Location: </label>
<select asp-for="Location" class="form-control" bind="#ro.Location">
<option value="">-- Select a Location --</option>
#foreach (var loc in Location)
{
<option value="#loc">#loc</option>
}
</select>
</div>
<div class="col-lg-2">
<label asp-for="Assigned" class="control-label">Assigned: </label>
<select asp-for="Assigned" class="form-control" bind="#ro.Assigned">
<option value="">-- Select an Employee --</option>
#foreach (var emp in Employee)
{
<option value="#emp">#emp</option>
}
</select>
</div>
<div class="col-lg-2">
<label asp-for="Status" class="control-label">Status: </label>
<select asp-for="Status" class="form-control" bind="#ro.Status">
<option value="">-- Select a Status --</option>
#foreach (var st in Status)
{
<option value="#st">#st</option>
}
</select>
</div>
</div>
<br />
<div class="row"><div class="col-lg-1"></div><div class="col-lg-10"><hr id="Double" /></div></div>
<div class="row">
<div class="col-lg-1"></div>
<div class="col-lg-10">
#if (sections.Count > 0)
{
foreach (var sec in sections)
{
<h3>Section #sec.SectionNumber</h3>
<div class="row">
<div class="col-lg-1"></div>
<div class="col-lg-5">
<label for="Failure" class="control-label">Failure: </label>
<input for="Failure" class="form-control" bind="#sec.Failure" readonly />
</div>
<div class="col-lg-1"></div>
<div class="col-lg-1">
<label><input type="checkbox" checked="#IsCApprovedChecked(sec)" /> Warranty</label>
</div>
<div class="col-lg-2">
<label><input type="checkbox" value="#IsWarrantyChecked(sec)" /> Repair Approved</label>
</div>
</div>
<div class="row">
<div class="col-lg-1"></div>
<div class="col-lg-10">
<label for="AdminComments" class="control-label">Admin Comments: </label>
<input for="AdminComments" class="form-control" bind="#sec.AdminComments" readonly />
</div>
</div>
<div class="row">
<div class="col-lg-1"></div>
<div class="col-lg-10">
<label for="TechComments" class="control-label">Tech Comments: </label>
<input for="TechComments" class="form-control" bind="#sec.TechComments" readonly />
</div>
</div>
}
}
</div>
</div>
<div class="row"></div>
</div> #*Form-group*#
</form>
<div class="row">
<div class="col-lg-1"></div>
<div class="col-lg-9">
<br /><br />
<button class="btn btn-primary float-right" onclick="#AddSectionCalled">Add New Section</button>
</div>
</div>
#if (isAddNew == true)
{
<div class="modal" tabindex="-1" style="display:block" role="dialog">
<div class="modal-dialog modal-dialog-scrollable modal-xl">
<div class="modal-content">
<div class="modal-header">
<h3 class="modal-title">New Repair Section</h3>
<button type="button" class="close" onclick="#CloseModal"><span aria-hidden="true">X</span></button>
</div>
<div class="modal-body">
<form>
<div class="row">
<div class="col-lg-1"></div>
<div class="col-lg-2">
<label for="sectionLetter" class="control-label">Section: </label>
<input for="sectionLetter" class="form-control" bind="#_newSection.SectionNumber" />
</div>
<div class="col-lg-1"></div>
<div class="col-lg-2">
<label><input type="checkbox" bind="#_newSection.Warranty" /> Warranty</label>
</div>
<div class="col-lg-2">
<label><input type="checkbox" bind="#_newSection.CustomerApproved" /> Repair Approved</label>
</div>
</div>
<div class="row">
<div class="col-lg-1"></div>
<div class="col-lg-10">
<label for="_failure" class="control-label">Failure: </label>
<input for="_failure" class="form-control" bind="#_newSection.Failure" />
</div>
</div>
<div class="row">
<div class="col-lg-1"></div>
<div class="col-lg-10">
<label for="_adminComments" class="control-label">Admin Comments: </label>
<input for="_adminComments" class="form-control" bind="#_newSection.AdminComments" />
</div>
</div>
<div class="row">
<div class="col-lg-1"></div>
<div class="col-lg-10">
<label for="_techComments" class="control-label">Tech Comments: </label>
<input for="_techComments" class="form-control" bind="#_newSection.TechComments" />
</div>
</div>
<br />
<button class="btn btn-primary float-left" onclick="AddNewSection()">Add New Section</button>
</form>
</div>
</div>
</div>
</div>
}
#functions
{
private RepairOrder ro;
private RepairOrder incomingRO;
private RepairOrderDataAccess RoData;
private string chassis;
private List<string> Location;
private List<string> Employee;
private List<string> Status;
private FileService fileService;
private List<RepairSection> sections;
private bool isAddNew;
//for new repair section modal
private RepairSection _newSection;
protected override async Task OnInitAsync()
{
ro = new RepairOrder();
Location = new List<string>();
Employee = new List<string>();
Status = new List<string>();
sections = new List<RepairSection>();
isAddNew = false;
fileService = new FileService();
RoData = new RepairOrderDataAccess(context);
await LoadData();
}
private async Task LoadData()
{
Location = await Task.Run(() => fileService.ReadLocation());
Employee = await Task.Run(() => fileService.ReadEmployees());
Status = await Task.Run(() => fileService.ReadStatus());
}
public string IsCApprovedChecked(RepairSection sc)
{
if (sc.CustomerApproved == true)
{
return "checked";
}
else
{
return "";
}
}
public string IsWarrantyChecked(RepairSection sc)
{
if (sc.Warranty == true)
{
return "checked";
}
else
{
return "";
}
}
protected void AddSectionCalled()
{
_newSection = new RepairSection();
this.isAddNew = true;
}
private void AddNewSection()
{
sections.Add(_newSection);
this.StateHasChanged();
this.isAddNew = false;
}
private void CloseModal()
{
this.isAddNew = false;
}
There is a problem with the way you have bound the onclick event of the button on the modal form.
you have onclick="AddNewSection()"
- writing it this way will likely be interpreted as a pure javascript call and if you inspect the DOM in your browser tools, you will likely see onclick="AddNewSection()" on the button.
You should have onclick="#AddNewSection"
- this way, Blazor will hook up the onclick event to your C# method.

Posting varying amount of images from a form

I'm attempting to build a form with a few textbox inputs and a file input for someone to upload images.
When a file is picked, I have some JS go get a partial view and render it in the form. After the new partial is rendered, I clone and copy the file input element and place it as a hidden input in the new partial to be used later in the form. There's some other fields in the partial that relate to the image that was selected.
Once that's all done, the file input element is reset, and the user can select another image, generating a new partial view, etc.
The form looks like it's being rendered correctly, but when I try to submit, VS memory/cpu usage spikes, and the request never makes it to the controller. Any advice or help here is appreciated!
Screenshot of the form
ViewModel:
public class ProjectCreate
{
public int Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public DateTime ProjectDate { get; set; }
public List<Image> GalleryImages { get; set; }
}
Image ViewModel:
public class Image
{
public int Id { get; set; }
public int GalleryIndex { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public IFormFile ImageFile { get; set; }
}
Form:
<form asp-action="Create" enctype="multipart/form-data">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group col-sm-4">
<label asp-for="Title" class="control-label"></label>
<input asp-for="Title" class="form-control" />
<span asp-validation-for="Title" class="text-danger"></span>
</div>
<div class="form-group col-sm-4">
<label asp-for="Description" class="control-label"></label>
<input asp-for="Description" class="form-control" />
<span asp-validation-for="Description" class="text-danger"></span>
</div>
<div class="form-group col-sm-4">
<label asp-for="ProjectDate" class="control-label"></label>
<input asp-for="ProjectDate" class="form-control" />
<span asp-validation-for="ProjectDate" class="text-danger"></span>
</div>
<div class="form-group col-sm-4">
<label class="control-label">Project Images</label>
<input id="ImageUpload" type="file" class="form-control" accept="image/jpeg, image/png, image/gif" />
</div>
#* Display images here *#
<div id="pending-images" class="row"></div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
The 'pending-images' div is where the partialview is rendered to.
PartialView:
<div class="card mb-3" style="width: 18rem">
<img class="card-img-top" id="pending-image-#Model.Id" src="" style="max-height: 18rem; max-width: 18rem;" />
<div class="card-body">
<div class="form-group">
<label class="control-label">Index</label>
<input id="GalleryImages[#Model.Id].GalleryIndex" name="GalleryImages[#Model.Id].GalleryIndex" class="form-control" value="#Model.Id" />
</div>
<div class="form-group">
<label class="control-label">Name/Title</label>
<input id="GalleryImages[#Model.Id].Name" name="GalleryImages[#Model.Id].Name" class="form-control" />
</div>
<div class="form-group">
<label class="control-label">Description</label>
<input id="GalleryImages[#Model.Id].Description" name="GalleryImages[#Model.Id].Description" class="form-control" />
</div>
<input type="file" id="GalleryImages[#Model.Id].ImageFile" name="GalleryImages[#Model.Id].ImageFile" style="display: none;" />
</div>
</div>
Rendered HTML:
<form enctype="multipart/form-data" action="/Projects/Create" method="post" novalidate="novalidate">
<div class="form-group col-sm-4">
<label class="control-label" for="Title">Title</label>
<input class="form-control valid" type="text" id="Title" name="Title" value="" aria-invalid="false">
<span class="text-danger field-validation-valid" data-valmsg-for="Title" data-valmsg-replace="true"></span>
</div>
<div class="form-group col-sm-4">
<label class="control-label" for="Description">Description</label>
<input class="form-control valid" type="text" id="Description" name="Description" value="" aria-invalid="false">
<span class="text-danger field-validation-valid" data-valmsg-for="Description"
data-valmsg-replace="true"></span>
</div>
<div class="form-group col-sm-4">
<label class="control-label" for="ProjectDate">Project Date</label>
<input class="form-control valid" type="date" data-val="true"
data-val-required="The Project Date field is required." id="ProjectDate" name="ProjectDate" value=""
aria-describedby="ProjectDate-error" aria-invalid="false">
<span class="text-danger field-validation-valid" data-valmsg-for="ProjectDate"
data-valmsg-replace="true"></span>
</div>
<div class="form-group col-sm-4">
<label class="control-label">Project Images</label>
<input id="ImageUpload" type="file" class="form-control" accept="image/jpeg, image/png, image/gif">
</div>
<div id="pending-images" class="row">
<div class="col-sm-4">
<div class="card mb-3" style="width: 18rem">
<img class="card-img-top" id="pending-image-0" src="data:image/jpeg;base64,xxx"
style="max-height: 18rem; max-width: 18rem;">
<div class="card-body">
<div class="form-group">
<label class="control-label">Index</label>
<input id="GalleryImages[0].GalleryIndex" name="GalleryImages[0].GalleryIndex"
class="form-control" value="0">
</div>
<div class="form-group">
<label class="control-label">Name/Title</label>
<input id="GalleryImages[0].Name" name="GalleryImages[0].Name" class="form-control">
</div>
<div class="form-group">
<label class="control-label">Description</label>
<input id="GalleryImages[0].Description" name="GalleryImages[0].Description"
class="form-control">
</div>
<input id="GalleryImages[0].ImageFile" type="file" class="form-control"
accept="image/jpeg, image/png, image/gif" name="GalleryImages[0].ImageFile"
style="display:none;">
</div>
</div>
</div>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary">
</div>
<input name="__RequestVerificationToken" type="hidden" value="xxx">
</form>
When there's more than one image trying to be uploaded, only the first image shows up the in the Fiddler info. I can also upload that or anything else if it would be helpful. I tried to include everything though. Is there a better way to accomplish this? I'm thinking about trying to hook into imgur or something similar if I can't work this out.
You should use your input like this :
<input type="file" multiple="multiple" name="files" id="files" />
I don't know if you can use the type="image" here, but you can certainly use your controler to check if the user only uploaded images.
Or you may be able to add this parameter to the input.
accept="image/png, image/jpeg"

Categories

Resources