Asp Net Core 2 Models in one page Validation - c#

To be short, I have 2 View Models, one is for creating and another for editing. The problem is to bypass ModelState validation for one of them. For example, I want to edit a user. When I post it will say validation is invalid for the Input Model which I do not want to use when I trigger the OnPostEdit handler. I tried to remove the key from ModelState but does not work because using debugger all the properties appear without the class which means I would have to remove all properties one by one by their names. The point is, how can I handle all of this without having to remove keys one by one? I know I could just create another page but it's better UX to have it all on one.
Also I found a similar post but has no solution, but should explain what I need better too.
Razor Pages - Model validation fails due to multiple objects sharing parameters
#if (Model.EditInput != null)
{
<form method="post" asp-page-handler="Edit">
<!-- Modal -->
<div class="modal fade" id="modalEditUser" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header bg-warning">
<h5 class="modal-title" id="exampleModalLabel"><i class="fas fa-edit"></i> Editar Utilizador</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true"><i class="fas fa-times"></i></span>
</button>
</div>
<div class="modal-body">
<input type="hidden" asp-for="EditInput.Id" />
<div class="form-row">
<div class="form-group col-md-12">
<label asp-for="EditInput.UserName"></label>
<input asp-for="EditInput.UserName" class="form-control rounded-0" />
<span asp-validation-for="EditInput.UserName" class="text-danger"></span>
</div>
</div>
<div class="form-row">
<div class="form-group col-md-12">
<label asp-for="EditInput.Name"></label>
<input asp-for="EditInput.Name" class="form-control rounded-0" />
<span asp-validation-for="EditInput.Name" class="text-danger"></span>
</div>
</div>
<div class="form-row">
<div class="form-group col-md-12">
<label asp-for="EditInput.Email"></label>
<input asp-for="EditInput.Email" class="form-control rounded-0" />
<span asp-validation-for="EditInput.Email" class="text-danger"></span>
</div>
</div>
<div class="form-row">
<div class="form-group col-md-12">
<label asp-for="EditInput.Password"></label>
<input asp-for="EditInput.Password" class="form-control rounded-0" />
<span asp-validation-for="EditInput.Password" class="text-danger"></span>
</div>
</div>
<div class="form-row">
<div class="form-group col-md-12">
<label asp-for="EditInput.ConfirmPassword"></label>
<input asp-for="EditInput.ConfirmPassword" class="form-control rounded-0" />
<span asp-validation-for="EditInput.ConfirmPassword" class="text-danger"></span>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancelar</button>
<button type="submit" class="btn btn-warning">Guardar</button>
</div>
</div>
</div>
</div>
</form>
}
<form method="post">
<!-- Modal -->
<div class="modal fade" id="modalAddUser" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header bg-lightblue">
<h5 class="modal-title" id="exampleModalLabel">Adicionar Artigo a Kit</h5>
<button type="button" class="close text-white" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true"><i class="fas fa-times"></i></span>
</button>
</div>
<div class="modal-body">
<div class="form-row">
<div class="form-group col-md-12">
<label asp-for="Input.UserName"></label>
<input asp-for="Input.UserName" class="form-control rounded-0" />
<span asp-validation-for="Input.UserName" class="text-danger"></span>
</div>
</div>
<div class="form-row">
<div class="form-group col-md-12">
<label asp-for="Input.Name"></label>
<input asp-for="Input.Name" class="form-control rounded-0" />
<span asp-validation-for="Input.Name" class="text-danger"></span>
</div>
</div>
<div class="form-row">
<div class="form-group col-md-12">
<label asp-for="Input.Email"></label>
<input asp-for="Input.Email" class="form-control rounded-0" />
<span asp-validation-for="Input.Email" class="text-danger"></span>
</div>
</div>
<div class="form-row">
<div class="form-group col-md-12">
<label asp-for="Input.Password"></label>
<input asp-for="Input.Password" class="form-control rounded-0" />
<span asp-validation-for="Input.Password" class="text-danger"></span>
</div>
</div>
<div class="form-row">
<div class="form-group col-md-12">
<label asp-for="Input.ConfirmPassword"></label>
<input asp-for="Input.ConfirmPassword" class="form-control rounded-0" />
<span asp-validation-for="Input.ConfirmPassword" class="text-danger"></span>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancelar</button>
<button type="submit" class="btn bg-lightblue">Adicionar</button>
</div>
</div>
</div>
</div>
</form>
Page Model
[BindProperty]
public EditUserVM EditInput { get; set; }
[BindProperty]
public UserVM Input { get; set; }
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
GetData();
_toast.AddErrorToastMessage("Dados inválidos.");
return Page();
}
// add user
_toast.AddSuccessToastMessage("Utilizador alterado.");
return RedirectToPage("Index");
}
public async Task<IActionResult> OnPostEditAsync()
{
ModelState.Remove(nameof(UserVM));
if (!ModelState.IsValid)
{
GetData();
_toast.AddErrorToastMessage("Dados inválidos.");
return Page();
}
var user = await _userManager.FindByIdAsync(EditInput.Id.ToString());
user.UserName = EditInput.UserName;
user.Name = EditInput.Name;
user.Email = EditInput.Email;
user.IsBlocked = EditInput.IsBlocked;
user.ModifiedAt = DateTime.Now;
var hashedPassword = _userManager.PasswordHasher.HashPassword(user, EditInput.Password);
user.PasswordHash = hashedPassword;
await _userManager.UpdateAsync(user);
_toast.AddSuccessToastMessage("Utilizador alterado.");
return RedirectToPage("Index");
}

So the solution is to wrap both models into one
For example instead of having this
[BindProperty]
public EditUserVM EditInput { get; set; }
[BindProperty]
public UserVM Input { get; set; }
I would create another class in my page and change the properties around the page accordingly. With this If I hit the Edit Handler, the UserVM won't appear on the ModelState and the same vice-versa
[BindProperty]
public FormModel Form { get; set; }
public class FormModel
{
public UserVM Input { get; set; }
public EditUserVM EditInput { get; set; }
}

Related

Handling two forms in View (ASP dotNet Core)

I have two forms in my view: One of them is modal and could get excel file. after importing excel file and proccessing its data -> i need these data in the other form of my view. How Can I Handle this?
i want when i submit excel import form, its data show in the first form for sending sms.
Here is my view code
<form asp-controller="Festival" asp-action="SendNotificationToCustomer" method="post">
<div class="card-body">
#await Component.InvokeAsync("AdminWidget", new { widgetZone = AdminWidgetZones.FestivalDetailsTop, additionalData = Model })
<div class="card card-default">
<div class="card-body">
<div class="form-group row" id="OperatorName-area">
<div class="col-md-12">
<div class="input-group">
<div class="col-md-6">
<div class="input-group">
<nop-select asp-for="SelectedCustomerRoleIdsForSms" asp-items="Model.AvailableCustomerRolesForSms" asp-multiple="true" />
</div>
<label asp-for="SMSPhonenumbers" />
<textarea asp-for="SMSPhonenumbers" asp-required="true" />
<span asp-validation-for="SMSPhonenumbers"></span>
</div>
<div class="col-md-6">
#Html.HiddenFor(x=>x.Id)
<label asp-for="TextMessage" />
<textarea asp-for="TextMessage" asp-required="true" />
<span asp-validation-for="TextMessage"></span>
</div>
<div class="input-group-append py-2">
<button type="submit" id="btnSendNotification" class="btn btn-info rounded-sm">
#T("Admin.festival.notification.Button")
</button>
</div>
<div class="input-group-append py-2 mr-2">
<button type="button" name="importexcel" class="btn bg-olive rounded-sm" data-toggle="modal" data-target="#importexcel-window">
<i class="fas fa-upload"></i>
#T("Admin.Common.Import")
</button>
</div>
<span>#Model.PhonenumbersFromExcel</span>
</div>
<span asp-validation-for="TextMessage"></span>
</div>
</div>
</div>
</div>
</div>
</form>
<div id="importexcel-window" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="importexcel-window-title">
<div class="modal-dialog">
<form asp-controller="Festival" asp-action="ImportPhonenumbersFromExcel" method="post" enctype="multipart/form-data">
<div class="form-horizontal">
<div class="modal-body">
<div class="form-group row">
<div class="col-md-2">
<div class="label-wrapper">
</div>
</div>
<div class="col-md-10">
<input type="file" id="importexcelfile" name="importexcelfile" class="form-control" />
<input type="hidden" id="currentId" name="currentId" value="#Model.Id" />
</div>
</div>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary"></button>
</div>
</div>
</form>
</div>
</div>
</div>

ASP.NET Core: Modal does not pass values to controller method

My index consists of a table that shows all my created questions (a survey). But I want to be able to edit a question using a modal. Therefore I have created the following modal in a foreach loop:
#foreach (var item in Model.Questions)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Id)
</td>
<td>
#Html.DisplayFor(modelItem => item.Question1)
</td>
<td>
#Html.DisplayFor(modelItem => item.ReplyOptions)
</td>
<td>
#Html.DisplayFor(modelItem => item.Group)
</td>
<td>
#if (item.CategoryId != null)
{
#Html.DisplayFor(modelItem => item.Category.Name)
}
else
{
<i><font color="red">Nicht zugewiesen</font></i>
}
</td>
<td>
<!-- Button trigger modal -->
<button type="button" class="btn btn-sm" data-toggle="modal" data-target="##item.Id">
Bearbeiten
</button>
<!-- Modal -->
<div class="modal fade" id="#item.Id" tabindex="-1" role="dialog" aria-labelledby="xxx" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<h2 class="modal-title" id="xxx">Frage bearbeiten</h2>
</div>
<div class="modal-body">
<form asp-action="Edit">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="#item.Id" />
<div class="form-group">
<label asp-for="#item.CategoryId" class="control-label"></label>
<select asp-for="#item.CategoryId" class="form-control" asp-items="ViewBag.CategoryId"></select>
<span asp-validation-for="#item.CategoryId" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="#item.Question1" class="control-label"></label>
<input asp-for="#item.Question1" class="form-control" />
<span asp-validation-for="#item.Question1" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="#item.ReplyOptions" class="control-label"></label>
<input asp-for="#item.ReplyOptions" class="form-control" />
<span asp-validation-for="#item.ReplyOptions" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="#item.Group" class="control-label"></label>
<input asp-for="#item.Group" class="form-control" />
<span asp-validation-for="#item.Group" class="text-danger"></span>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary">Save</button>
</div>
</form>
</div>
</div>
</div>
</div>
<a asp-action="Delete" asp-route-id="#item.Id">Delete</a>
</td>
</tr>
}
But I have the following problem:
When I want to edit the question and click on Save, my Edit method in the controller does not get the values.
The method looks like this:
What do I have to do to ensure that the values are passed on?
What do I have to do to ensure that the values are passed on?
Just to add name attribute to each control in the form :
<div class="modal-body">
<form asp-action="Edit">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="#item.Id" name="Id" />
<div class="form-group">
<label asp-for="#item.CategoryId" class="control-label"></label>
<select asp-for="#item.CategoryId" class="form-control" asp-items="ViewBag.CategoryId" name="CategoryId"></select>
<span asp-validation-for="#item.CategoryId" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="#item.Question1" class="control-label"></label>
<input asp-for="#item.Question1" class="form-control" name="Question1" />
<span asp-validation-for="#item.Question1" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="#item.ReplyOptions" class="control-label"></label>
<input asp-for="#item.ReplyOptions" class="form-control" name="ReplyOptions" />
<span asp-validation-for="#item.ReplyOptions" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="#item.Group" class="control-label"></label>
<input asp-for="#item.Group" class="form-control" name="Group" />
<span asp-validation-for="#item.Group" class="text-danger"></span>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary">Save</button>
</div>
</form>
</div>
Here is the test result:

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"

Show <select> values in PartialView ASP.NET Core

I migrate project from ASP.NET MVC to ASP.NET Core
I was having Partial view with two daropdowns
So Controller method was like this
public ActionResult AddPeopleToProposal()
{
ViewBag.Worker = new SelectList(db.People, "Id", "FIO").ToList();
ViewBag.Proposal = new SelectList(db.Proposals, "Id", "Id").ToList();
return PartialView("AddPeopleToProposal");
}
And in View I was render it like this
<div class="modal fade" id="addPeopleToProposal" tabindex="-1" role="dialog" aria-labelledby="exampleModalCenterTitle" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLongTitle">Добавить работника на заявку</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
#Html.Action("AddPeopleToProposal", "Manage")
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Отмена</button>
<button type="button" id="peopleToProposalCreate" class="btn btn-primary">Создать</button>
</div>
</div>
</div>
And Partial View
<form>
<div class="form-group">
<label for="recipient-name" class="col-form-label">Працівник</label>
#Html.DropDownList("Worker", null, "XXXX", htmlAttributes: new { #class = "form-control", #id = "peopleIdAdd" })
</div>
<div class="form-group">
<label for="recipient-name" class="col-form-label">Оберіть заявку</label>
#Html.DropDownList("Proposal", null, "XXXX", htmlAttributes: new { #class = "form-control", #id = "proposalIdAdd" })
</div>
<div class="form-group">
<label for="message-text" class="col-form-label">Коментар</label>
<input type="text" class="form-control" id="commentVchasno" >
</div>
But as I know #Html.Action was depricated
I realize this in Core like this
Controller
public ActionResult AddPeopleToProposal()
{
ViewData["Worker"] = new SelectList(_context.People, "Id", "FIO");
ViewData["Proposal"] = new SelectList(_context.Proposals, "Id", "Id");
return PartialView("Partials/AddPeopleToProposal");
}
And Partial View
<form>
<div class="form-group">
<label class="col-form-label">Працівник</label>
<select class="form-control" asp-items="ViewBag.Worker"></select>
</div>
<div class="form-group">
<label class="col-form-label">Оберіть заявку</label>
<select class="form-control" asp-items="ViewBag.Proposal"></select>
</div>
<div class="form-group">
<label class="col-form-label">Коментар</label>
<input type="text" class="form-control" id="commentVchasno" >
</div>
</form>
And View from where I cal Partial
<div class="modal fade" id="addPeopleToProposal" tabindex="-1" role="dialog" aria-labelledby="exampleModalCenterTitle" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLongTitle">Добавить работника на заявку</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
#Html.Partial("Partials/AddPeopleToProposal")
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Отмена</button>
<button type="button" id="peopleToProposalCreate" class="btn btn-primary">Создать</button>
</div>
</div>
</div>
But at Core I don't have values in selects. Where is my problem?
If you want to initialize the page directly when getting the Partial View, try to put the following two lines of code into the get request of the main View of the Partial View. More about Partial views
ViewData["Worker"] = new SelectList(_context.People, "Id", "FIO");
ViewData["Proposal"] = new SelectList(_context.Proposals, "Id", "Id");
Or you could use the ViewComponent instead of the Partial View to get the fill data of the dropdownlists from the Invoke method in the view component class. Try to the code like below
ViewComponent.cs
public class AddPeopleToCountryViewComponent:ViewComponent
{
private readonly MVCDbContext _context;
public AddPeopleToCountryViewComponent(MVCDbContext context)
{
_context = context;
}
public async Task<IViewComponentResult> InvokeAsync(
int maxPriority, bool isDone)
{
ViewData["Customer"] = new SelectList(_context.Customer, "Id", "Name");
ViewData["Country"] = new SelectList(_context.Country, "Id", "Id");
return View();
}
}
The Default.cshtml of ViewComponent
<form>
<div class="form-group">
<label class="col-form-label">People</label>
<select class="form-control" asp-items="#ViewBag.Customer"></select>
</div>
<div class="form-group">
<label class="col-form-label">Country</label>
<select class="form-control" asp-items="#ViewBag.Country"></select>
</div>
<div class="form-group">
<label class="col-form-label">Comment</label>
<input type="text" class="form-control" id="commentVchasno">
</div>
Instead of the PartialView in the modal of the main view
<div class="modal-body">
#await Component.InvokeAsync("AddPeopleToCountry", new { })
</div>

Categories

Resources