Passing List of Model Class From A View to A Controller in Asp.NetCore - asp.net-core-2.2

i'm currently trying to post a a list of ModelClass(FileInfo) to my controller, but the submit doesn't seem to call the controller at all,even when i debug, the process does not enter my Controller Action, below is my View Code(claimdocumentform.cshtml),
#model IList<PIBSSBus.DomainModels.FileInfo>
<form method="POST" enctype="multipart/form-data">
<table class="table table-striped table-hover table-bordered" id="sample_editable_1">
<thead>
<tr>
<th> Document</th>
<th> Submitted </th>
<th> Date Submitted </th>
<th> # </th>
</tr>
</thead>
<tbody>
<tr>
<td> <input type="text" placeholder="title" asp-for="#Model[0].Title" value="enter"> </td>
<td><input type="text" placeholder="Description" asp-for="#Model[0].Description" value="enter1"> </td>
<td> </td>
<td>
<input type="file" class="" asp-for="#Model[0].File" value="Upload">
</td>
</tr>
<tr>
<td> <input type="text" placeholder="title" asp-for="#Model[1].Title" value="enter2"> </td>
<td><input type="text" placeholder="Description" asp-for="#Model[1].Description" value="enter3"> </td>
<td> </td>
<td>
<input type="file" class="" asp-for="#Model[1].File" value="Upload">
</td>
</tr>
#* #Html.AntiForgeryToken();*#
</tbody>
</table>'
<button type="submit" asp-controller="Claims" asp-action="Wazobia" class="btn green button-submit">
Submit
<i class="fa fa-check"></i>
</button>
</form>
This is my controller
public IActionResult claimdocumentform()
{
//PIBSSBus.DomainModels.FileInfo something = new PIBSSBus.DomainModels.FileInfo();
// IList<PIBSSBus.DomainModels.FileInfo> filess =new List<PIBSSBus.DomainModels.FileInfo>();
return View();
}
// [ValidateAntiForgeryToken]
[HttpPost]
public IActionResult Wazobia(IList<PIBSSBus.DomainModels.FileInfo> fam)
{
return View();
}
this is my model class
public class FileInfo
{
public string Title { get; set; }
public string Description { get; set; }
[DataType(DataType.Upload)]
public IFormFile File { get; set; }
}
The issue i am trying to pass the list of FileInfo class containing two rows to my controller action Wazobia but it doesn't call the action at all, pls help

I firstly tested the code in asp.net core 3.0 and it works well(You could also try this). Then I tried in asp.net core 2.2 MVC and it does not work like yours.
Then I find that it is a bug in asp.net core 2.2 and is fixed in asp.net core 3.0,refer to https://github.com/dotnet/core/issues/2523#issuecomment-481120637
A workaround is that you receive the files outside of the model
public class FileInfoVM
{
public string Title { get; set; }
public string Description { get; set; }
}
public class FileInfo
{
public string Title { get; set; }
public string Description { get; set; }
public IFormFile File { get; set; }
}
View:
<tbody>
<tr>
<td> <input type="text" placeholder="title" asp-for="#Model[0].Title" value="enter"> </td>
<td><input type="text" placeholder="Description" asp-for="#Model[0].Description" value="enter1"> </td>
<td> </td>
<td>
<input type="file" class="" name="Files">
</td>
</tr>
<tr>
<td> <input type="text" placeholder="title" asp-for="#Model[1].Title" value="enter2"> </td>
<td><input type="text" placeholder="Description" asp-for="#Model[1].Description" value="enter3"> </td>
<td> </td>
<td>
<input type="file" class="" name="Files">
</td>
</tr>
</tbody>
Action;
[ValidateAntiForgeryToken]
[HttpPost]
public IActionResult Wazobia(IList<PIBSSBus.DomainModels.FileInfoVM> fam,List<IFormFile> Files)
{
List<FileInfo> fileInfos = new List<FileInfo>();
for(int i= 0; i< Files.Count; i++)
{
fileInfos.Add(new FileInfo()
{
Title = fam[i].Title,
Description = fam[i].Description,
File = Files[i]
});
}
// save fileInfos
return View();
}

Related

How to implement Search Functionality

i create search bar in nav i want to search Member in nav bar and i have create bootstrap cards on home page
This is My Member Model
public class Member
{
[Key]
public int MemberId { get; set; }
[StringLength(60, MinimumLength = 3)]
public string? Name { get; set; }
public string? Gender { get; set; }
public DateTime DOB { get; set; }
public string? MaritalStatus { get; set; }
public string? Address { get; set; }
public long PhoneNo { get; set; }
public string? Skills { get; set; }
public string? Hobbies { get; set; }
public string? JobTitle { get; set; }
public string? Technology { get; set; }
public string? ImageName { get; set; }
public string? ImageLocation { get; set; }
public Team? Team { get; set; }
public ICollection<TeamMember>? TeamMembers { get; set; }
public ICollection<ProjectMember>? ProjectMembers { get; set; }
}
This is my View of search Bar
<form class="d-none d-md-inline-block form-inline ms-auto me-0 me-md-3 my-2 my-md-0">
<div class="input-group">
<input class="form-control" type="text" placeholder="Search for..." aria-label="Search" aria-describedby="btnNavbarSearch" />
<button class="btn btn-primary" id="btnNavbarSearch" type="button">Search</button>
</div>
</form>
I create search bar in nav I want to search Member in nav bar and I have create bootstrap cards on home page
Though your given code is not adequate to provide a complete example
for your scenario, you could implement a search option using ViewData functionality roughly by following the below steps.
How It works
By default, we will load all the members on our Index page. Because
at the beginning search key will be empty. So we have set the conditional for that. After loading all the member List now we can search. When we enter any search key it will submit the value to
the controller using ViewData["CurrentFilter"] and finally will
search into the database by that search key and return the view
back.
Controller
public IActionResult Index( string searchString)
{
ViewData["CurrentFilter"] = searchString;
var members = from mem in _context.Members
select mem;
if (!String.IsNullOrEmpty(searchString))
{
members = members.Where(m => m.Name.Contains(searchString)
|| m.Gender.Contains(searchString));
return View(members);
}
var memberList = _context.Members.ToList();
return View(memberList);
}
Note: Currently, we have implemented searching on Member Name and Gender you can extend to other properties as well by simply adding
|| or Like this way:
members = members.Where(m => m.Name.Contains(searchString)
|| m.Gender.Contains(searchString || any Other Fields));
View
#model IEnumerable<DotNet6MVCWebApp.Models.Member>
#{
ViewData["Title"] = "Index";
}
<div class="form-row">
<table>
<tr>
<td>
<a asp-action="CreateMemberView" class="btn btn-success">Create New</a>
</td>
</tr>
</table>
</div>
<table class="table">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.Name)
</th>
<th>
#Html.DisplayNameFor(model => model.Gender)
</th>
<th>
#Html.DisplayNameFor(model => model.DOB)
</th>
<th>
#Html.DisplayNameFor(model => model.ImageName)
</th>
<th>
Member Details
</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.Gender)
</td>
<td>
#Html.DisplayFor(modelItem => item.DOB)
</td>
<td>
<img src="~/ImageName/Cover/#item.ImageName"
class="rounded-square"
height="50" width="75"
style="border:1px"
asp-append-version="true" accept="image/*" />
</td>
<td>
<a asp-action="Details" class="btn btn-primary" asp-route-memberId="#item.MemberId">Details</a> | <a asp-action="EditMember" class="btn btn-warning" asp-route-memberId="#item.MemberId">Edit</a>
</td>
</tr>
}
</tbody>
</table>
Nav Bar
<li class="nav-item">
<div class="form-row">
<table>
<tr>
<form method="get" action="/YourController/Index">
<td style="padding-right:940px">
</td>
<td>
<input class="form-control" type="text" placeholder="Search for..." name="SearchString" value="#ViewData["CurrentFilter"]" aria-label="Search" aria-describedby="btnNavbarSearch" />
</td>
<td>
<input type="submit" value="Search" class="btn btn-primary" />
</td>
</form>
</tr>
</table>
</div>
Output
If you need any further assistance on this, please see our official document here.

Model not capturing dynamic input fields [duplicate]

This question already has answers here:
MVC Form not able to post List of objects
(3 answers)
Closed 3 years ago.
I have a view model InvoiceViewModel and inside the InvoiceViewModel I have a property Items which is type list.
public class InvoiceViewModel
{
[Key]
public int InvoiceNumber { get; set; }
public int ClientID { get; set; }
public List<ItemsViewModel> Items { get; set; }
...
}
The ItemsViewModel model looks like this
public class ItemsViewModel
{
public string Name { get; set; }
public string UnitPrice { get; set; }
public string Quantity { get; set; }
public string TotalAmount { get; set; }
}
The following fields get added into the HTML using jQuery dynamically
<tr id="InvoiceLine-606818967">
<td class="text-left line-description">
<textarea name="Items[].Name" id="line-description-606818967" class="band autogrow" rows="1"></textarea>
</td>
<td class="text-right line-unit-cost">
<input type="number" name="Items[].UnitPrice" placeholder="0.00" min="0.00" step="0.01">
</td>
<td class="text-right line-quantity">
<input type="number" name="Items[].Quantity" placeholder="0">
</td>
</tr>
<tr id="InvoiceLine-2196849859">
<td class="text-left line-description">
<textarea name="Items[].Name" id="line-description-2196849859" class="band autogrow" rows="1"></textarea>
</td>
<td class="text-right line-unit-cost">
<input type="number" name="Items[].UnitPrice" placeholder="0.00" min="0.00" step="0.01">
</td>
<td class="text-right line-quantity">
<input type="number" name="Items[].Quantity" placeholder="0">
</td>
</tr>
<tr id="InvoiceLine-7114958211">
<td class="text-left line-description">
<textarea name="Items[].Name" id="line-description-7114958211" class="band autogrow" rows="1"></textarea>
</td>
<td class="text-right line-unit-cost">
<input type="number" name="Items[].UnitPrice" placeholder="0.00" min="0.00" step="0.01">
</td>
<td class="text-right line-quantity">
<input type="number" name="Items[].Quantity" placeholder="0">
</td>
</tr>
When the form is submitted, the following is what I see during debugging of the InvoiceViewModel
Please advise what am I doing wrong?
I don't know your error message but maybe you can write Items[iterationIndex].Quantity or item.Quantity etc. Probably when submit your form, model not know which index is mine

The Input Tag Helper are not found in cshtml.cs

I try to use the following expemple of Input Tag Helper in my code, but it isn´t working.
https://learn.microsoft.com/de-de/aspnet/core/mvc/views/working-with-forms?view=aspnetcore-2.2
https://www.learnrazorpages.com/razor-pages/tag-helpers/input-tag-helper
I want to use a list of objects to display in a table and read there values from inputs. Display the data works, but not reading the Inputs.
cshtml
#page
#{
var days2 = #Model.days;
}
<form class="form-horizontal" method="post">
<button asp-page-handler="Go" type="submit" class="btn btn-default">Go</button>
<table class="table">
<thead>
<tr>
<th>#Html.DisplayNameFor(m => m.days[0].Name)</th>
<th>#Html.DisplayNameFor(m => m.days[0].Beginn)</th>
........
</tr>
</thead>
<tbody>
#for (int i =0; i< days2.Count; i++)
{
<tr>
<td><input asp-for="#days2[i].Name" class="form-control" value=Tag.Name /></td>
<td><input asp-for="#days2[i].Beginn" class="form-control" value=Tag.Beginn /></td>
.....
</tr>
}
</tbody>
</table>
</form>
cshtml.cs
[BindProperty]
public List<day> days { get; set; }
public void OnGet()
{
days=getdaysvalue();
}
public void OnPostGo()
{
for (int i = 0; i < Tage.Count; i++)
{
days[i].Name = days2[i].Name; //days2 is in the actuell context not given
days[i].Beginn = days2[i].Beginn;
}
days2 is in the actuell context not given
you have several properties with same name and an ID in the view, and in the end it just reads the value of one of the properties.
you can try this
#for (int i =0; i< days2.Count; i++)
{
<tr>
<td><input id="Name_#i" type="text" name="Name" class="form-control" value="#Tag.Name" /></td>
<td><input id="Beginn_#i" type="text" name="Beginn" class="form-control" value="#Tag.Beginn" /></td>
.....
</tr>
}
and in the RazorPage
public void OnPostGo(List<string> Name,List<string> Beginn)
{
for (int i = 0; i < Tage.Count; i++)
{
days[i].Name = Name[i];
days[i].Beginn = Beginn[i];
}
}
For Razor Page, it helps to bind the model with [BindProperty] public List<day> days { get; set; }, you should try to access the submit model by days instead of variable in view.
Try like:
PageModel
public class TestModel : PageModel
{
[BindProperty]
public List<day> days { get; set; }
public void OnGet()
{
days = new List<day> {
new day{ Name = "D1", Beginn = "B1"},
new day{ Name = "D2", Beginn = "B2"},
new day{ Name = "D3", Beginn = "B3"},
};
}
public void OnPostGo()
{
var result = days;
}
}
View
#page
#model CoreRazor.Pages.Books.TestModel
#{
ViewData["Title"] = "Test";
}
<h1>Test</h1>
<form class="form-horizontal" method="post">
<button asp-page-handler="Go" type="submit" class="btn btn-default">Go</button>
<table class="table">
<thead>
<tr>
<th>#Html.DisplayNameFor(m => m.days[0].Name)</th>
<th>#Html.DisplayNameFor(m => m.days[0].Beginn)</th>
........
</tr>
</thead>
<tbody>
#for (int i = 0; i < Model.days.Count; i++)
{
<tr>
<td><input asp-for="#Model.days[i].Name" class="form-control" /></td>
<td><input asp-for="#Model.days[i].Beginn" class="form-control" /></td>
</tr>
}
</tbody>
</table>
</form>

Showing a List in a View then passing it to a HttpPost

Hi this is very simple but is not working for me.
This is my View:
#model iLeadsTest.ViewModels.SaveViewModel
#using (Html.BeginForm("Save", "Clients", FormMethod.Post))
{
<div>
<table class="table">
<thead>
<tr>
<th>Pin Number</th>
<th>First Name</th>
<th>Last Name</th>
</tr>
</thead>
<tbody>
#for (int i = 0; i < Model.FileClasses.Count; i++)
{
<tr>
<td>#Html.DisplayFor(m => m.FileClasses[i].PinNumberProperty)
</td>
<td>#Html.DisplayFor(m => m.FileClasses[i].FirstNameProperty)
</td>
<td>#Html.DisplayFor(m => m.FileClasses[i].LastNameProperty)
</td>
</tr>
}
</tbody>
</table>
</div>
#Html.HiddenFor(m=>m.FileName);
<input class="btn btn-primary" type="submit" name="Submit" id="Submit" value="Upload" />
}
My ViewModel:
public class SaveViewModel
{
public string FileName { get; set; }
public List<Clients> FileClasses { get; set; }
}
Why when I go to the method in my controller I'm getting an empty list?

refactor Html.LabelFor, EditorFor, ValidationMessageFor into partial view

I want to refactor view form code to avoid copyPaste. But it's not working. Razor don't allow to write
#model System.Linq.Expressions.Expression<Func<TModel, TValue>> expression
and
#Html.Partial("Item", model => model.EmpName)
Old code, that working:
<tr>
<td class="editor-label" style="border: 0;">
#Html.LabelFor(model=>model.EmpName)
</td>
<td class="editor-field" style="border: 0">
#Html.EditorFor(model=>model.EmpName)
#Html.ValidationMessageFor(model=>model.EmpName)
</td>
</tr>
<tr>
<td class="editor-label" style="border: 0;">
#Html.LabelFor(model=>model.Email)
</td>
<td class="editor-field" style="border: 0;">
#Html.EditorFor(model=>model.Email)
#Html.ValidationMessageFor(model=>model.Email)
</td>
</tr>
After refactoring not working:
Item.cshtml:
#model System.Linq.Expressions.Expression<Func<TModel, TValue>> expression
<tr>
<td class="editor-label" style="border: 0;">
#Html.LabelFor(expression)
</td>
<td class="editor-field" style="border: 0">
#Html.EditorFor(expression)
#Html.ValidationMessageFor(expression)
</td>
</tr>
}
New code:
#Html.Partial("Item", model => model.EmpName)
#Html.Partial("Item", model => model.Email)
How to make it work?
You can write your own HtmlHelper extension method, something like:
public static MvcHtmlString MyEditFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression)
{
var group = new TagBuilder("div");
group.InnerHtml = html.LabelFor(expression).ToString();
//more formatting and controls here
return MvcHtmlString.Create(group.ToString());
}
This will allow you to write:
#Html.MyEditFor(m => m.Name)
The drawback of this approach is that you won't be able to inline HTML because this is not a view. However it does allow you to set up a standard control layout.
The solution was found. Thanx to #Paul.
Item.cshtml:
#model MyClientCustomValidation.Models.LabelEditorValidation
<tr>
<td class="editor-label" style="border: 0;">
#Model.Label
</td>
<td class="editor-field" style="border: 0">
#Model.Editor
#Model.Validation
</td>
</tr>
Which has model:
public class LabelEditorValidation
{
public MvcHtmlString Label { get; set; }
public MvcHtmlString Editor { get; set; }
public MvcHtmlString Validation { get; set; }
}
And inside form:
#Html.MyEditFor(model=>model.EmpName)
#Html.MyEditFor(model=>model.Email)
Where MyEditorFor is
public static MvcHtmlString MyEditFor<TModel, TProperty>(this HtmlHelper<TModel> html, Expression<Func<TModel, TProperty>> expression)
{
return html.Partial("Item", new LabelEditorValidation() { Label = html.LabelFor(expression), Editor = html.EditorFor(expression), Validation = html.ValidationMessageFor(expression) });
}

Resources