How to pass multiple checkbox parameters from foreach - c#

I have a form in my View with a table and on each cell i have a checkbox. I already have individual Ids for every single checkbox but I dont know how to pass them individually to controller action. I know how to pass single parameters over the "name" attribute but Im not sure on how to handle it with so many diffrent checkboxes.
View
#{
bool IsOwnRegistration = false;
foreach (var item in Model.Events.Where(i => i.UserId == Model.UserID && Convert.ToDateTime(i.Date) > dateTime))
{
if (item.HasCreatedOtherUsers == null)
{
IsOwnRegistration = true;
}
string Surname = "";
string Lastname = "";
<tr>
#{
foreach (var Useritem in Model.Users.Where(i => i.UserId == item.HasCreatedOtherUsers))
{
Surname = Useritem.Vorname;
Lastname = Useritem.Nachname;
}
if (IsOwnRegistration == true)
{
<th style="background-color:grey; width:33%;">
Meine Reservation
</th>
<th style="width:33%;">#item.Date</th>
<th style="width:33%;">
<div class="custom-control custom-checkbox ">
<input type="checkbox" class="custom-control-input" name="#item.EventId" id="#item.Date#item.EventId">
<label class="custom-control-label" for="#item.Date#item.EventId"><i style="color:red;" class="fas fa-trash-alt"></i>
</label>
</div>
</th>
}
else
{
<th style="width:33%;">#Surname #Lastname</th>
<th style="width:33%;">#item.Date</th>
<th style="width:33%;">
<div class="custom-control custom-checkbox ">
<input type="checkbox" class="custom-control-input" name="#item.EventId" id="#item.Date#item.EventId">
<label class="custom-control-label" for="#item.Date#item.EventId"><i style="color:red;" class="fas fa-trash-alt"></i>
</label>
</div>
</th>
}
}
Controller
public ActionResult DeleteRegistrations(Need to get values of all checkboxes)
{
return RedirectToAction("HomePage");
}

In order to transmit the selected checkboxes to the action method, the checkboxes should share a common name that matches the parameter name of the action method. The following sample shows a Razor view that lists some strings in a table, creating a checkbox for each string:
#model IEnumerable<string>
#{
ViewBag.Title = "Home Page";
}
<div class="row">
<div class="col-md-12">
#using (Html.BeginForm("Index", "Home", FormMethod.Post))
{
<table>
#foreach (var s in Model)
{
<tr>
<td>
<input type="checkbox" name="selectedValues" value="#s" id="#s" />
<label for="#s">#s</label>
</td>
</tr>
}
</table>
<input type="submit" />
}
</div>
</div>
Please note that the name attribute of the checkboxes is set to "selectedValues", the value attribute is set to the original string (or an id in a more complex scenario).
The form is submitted by a POST request to the following action method:
[HttpPost]
public ActionResult Index(IEnumerable<string> selectedValues)
{
return View(selectedValues);
}
In the POST request, all the values of all checked checkboxes are transmitted as key value pairs in the form "name=value". As all of the checkboxes share the same name, ASP.NET MVC can deserialize this into an IEnumerable<string>.

Related

Return ViewData from view to controller razor pages

I have view is C#:
#{
var itemList = (List<Item>)ViewData["itemsList"];
}
<div class="row" style="margin-top: 10px;">
<div class="col-md-6">
#if (itemList != null)
{
var id = 0;
<table class="table table-striped">
<thead>
<tr>
<th>#</th>
<th></th>
<th>Id</th>
<th>Type</th>
</tr>
</thead>
<tbody>
#foreach (var result in itemsList)
{
<tr>
<td>#(++id)</td>
<td><input type="checkbox" value="true" #(result.Checked ? "checked" : "")></td>
<td>#result.Id</td>
<td>#result.Type</td>
</tr>
}
</tbody>
</table>
}
<div class="row justify-content-end" style="margin-top: 20px;">
<div class="col-md-2">
<form asp-controller="Control" asp-action="Remove" method="post">
<input type="hidden" name="tableName" value="table"/>
<input type="hidden" name="items" value="#itemList"/>
<div style="margin-left: -10px;" class="col-md-2">
<button class="btn btn-danger" title="Remove" type="submit">Remove</button>
</div>
</form>
</div>
</div>
</div>
</div>
I want to remove items from table, where user checks the checkbox. My idea was to update each checked item withing the list (result.Checked property) and then send array to Remove method:
[HttpPost]
public async Task<IActionResult> Remove(string tableName, List<ChangeQueueItem> items)
{
try
{
var toDelete = items.Where(x => x.Checked == true);
await _repository.RemoveFromQueue(toDelete, tableName);
}
catch (Exception e)
{
TempData["error"] = e.Message;
}
return RedirectToAction("Index");
}
I am trying to send that list like this:
<input type="hidden" name="items" value="#itemList"/>
however the value is null. How should I do it?
Update: data is loaded here:
[HttpGet]
public async Task<IActionResult> Index()
{
var items = await _repository.GetAll();
ViewData["itemsList"] = items;
ViewData["error"] = TempData["error"];
return View("Index");
}
First, you set value using ViewData["itemsList"] = items;, but get it by var itemList = (List<Item>)ViewData["itemList"];.
Change key value to be consistent: for example, replace itemList by itemsList in the view.
Second, to pass list from the view to the controller action method apply indexes to the items (only the <tbody> content is shown):
<tbody>
#using (Html.BeginForm("Remove", "Control"))
{
#Html.Hidden("tableName", "table")
#for (int i = 0; i < itemsList.Count; i++)
{
#Html.Hidden("items[" + i + "].Id", itemsList[i].Id)
#Html.Hidden("items[" + i + "].Type", itemsList[i].Type)
<tr>
<td>#(++id)</td>
<td>#Html.CheckBox("items[" + i + "].Checked", itemsList[i].Checked)</td>
<td>#itemsList[i].Id</td>
<td>#itemsList[i].Type</td>
</tr>
}
<tr><td><button class="btn btn-danger" title="Remove" type="submit">Remove</button></td></tr>
}
</tbody>
Or the same without the helper (only the <tbody> content is shown):
<tbody>
<form asp-controller="Control" asp-action="Remove" method="post">
<input type="hidden" name="tableName" value="table" />
#for (int i = 0; i < itemsList.Count; i++)
{
<input type="hidden" name="#("items[" + i + "].Id")" value="#itemsList[i].Id" />
<input type="hidden" name="#("items[" + i + "].Type")" value="#itemsList[i].Type" />
<tr>
<td>#(++id)</td>
<td><input name="#("items[" + i + "].Checked")" type="checkbox" value="true" #(itemsList[i].Checked ? "checked" : " ") /></td>
<td>#itemsList[i].Id</td>
<td>#itemsList[i].Type</td>
</tr>
}
<tr><td><button class="btn btn-danger" title="Remove" type="submit">Remove</button></td></tr>
</form>
</tbody>
It doesn't appear that you're setting the TempData["itemList"]; I can't see it in the code.
You should be setting it using something like:
TempData["itemList"] = toDelete;

Showing partial-view, only after search has been submitted Asp.Net MVC

I am new to Asp.Net Mvc. I couldn't find a solution that worked for me here, if I am blind just redirect me.
I am trying to make a web-app where i can search through clients, without displaying the entire table of clients. Only after the user presses search, the search result should show as a partial view. I understand that using Ajax is the most popular way of handling something like this.
Any pointers on how to accomplish this?
My first thought was to just make a display: block/none script connected to the submit button but the page updates each time you search rendering this idea useless. That's why i could use some help with how to asynchronously update the web page with the search result.
HomeController:
using testForAutofill.Models;
//Search Functionality
[HttpPost]
public PartialViewResult Index(string searchTerm)
{
test_Db_Context db = test_Db_Context();
List<ViewNewOrderSum> orderSums;
if (string.IsNullOrEmpty(searchTerm))//Fix this.
{
orderSums = db.ViewNewOrderSum.ToList();
}
else
{
orderSums = db.ViewNewOrderSum.Where(x =>
x.ClientName.Equals(searchTerm)).ToList();
}
return PartialView(orderSums);
}
Index View:
#model IEnumerable<testForAutofill.Models.ViewNewOrderSum>
#using (Html.BeginForm())
{
<b>Kundenavn:</b>
#Html.TextBox("searchTerm", null, new { id = "txtSearch" })
<input type="submit" value="🔍 Search" class="btn btn-primary" id="btn-search" />
}
<div id="posts-wrapper"></div>
<div class="client-div" runat="server" style="max-width: 20rem;">
<div class="card-header">Header</div>
<div class="card-body" id="client-Card">
<h4 class="card-title">Client info</h4>
<table id="client-table">
<tr>
<th>
#Html.DisplayNameFor(model => model.ClientName)
</th>
</tr>
#foreach (var item in Model)
{
#Html.Partial("_OrderSum", item)
}
</table>
</div>
</div>
Partial View:
#model testForAutofill.Models.ViewNewOrderSum
<tr>
<td>
#Html.DisplayFor(modelItem => Model.ClientName)
</td>
</tr>
No need of using Ajax. You can submit search text in Form Post. Fetch your data and filter based on your searchTerm retun to View with model. If your model is not null or empty show table else do not display table.
Checkout the below code :
View :
#model List<testForAutofill.Models.ViewNewOrderSum>
#using (Html.BeginForm()) {
<b>Kundenavn:</b>
#Html.TextBox("searchTerm", null, new { id = "txtSearch" })
<input type="submit" value="🔍 Search" class="btn btn-primary" id="btn-search" />
}
#if (Model != null && Model.Count() > 0) {
<div class="client-div" runat="server" style="max-width: 20rem;">
<div class="card-header">Header</div>
<div class="card-body" id="client-Card">
<h4 class="card-title">Client info</h4>
<table id="client-table">
<tr>
<th>
ClientName
</th>
</tr>
#foreach (var item in Model) {
#Html.Partial("_OrderSum", item)
}
</table>
</div>
</div>
}
Controller :
public ActionResult Index()
{
//if you want to load all the clients by default
test_Db_Context db = test_Db_Context();
List<ViewNewOrderSum> orderSums;
orderSums = db.ViewNewOrderSum.ToList();
return View(orderSums);
}
[HttpPost]
public ActionResult Index(string searchTerm) {
test_Db_Context db = test_Db_Context();
List<ViewNewOrderSum> orderSums;
if (!string.IsNullOrEmpty(searchTerm))
{
orderSums = db.ViewNewOrderSum.Where(x =>
x.ClientName.Equals(searchTerm)).ToList();
}
return View(result);
}
My first thought was to just make a display: block/none script
connected to the submit button but the page updates each time you
search rendering this idea useless.
You can prevent the page from updating using something like the following (using jQuery):
<script type="text/javascript">
$('form').submit(function (evt) {
evt.preventDefault();
... your code
});
</script>
Then you can make your ajax POST call, get the data, unhide table headers and append the html results from your partial view.

Asp.net Core MVC - on form posting to controller IEnumerable model in controller action is empty

I have a problem when I am trying to post IEnumerable from razor view to Controllor action method. Also result is the same if I use List.
I post my controllor action method also in comment. In my controllor action method I got list that is empty.
This is my View:
#model IEnumerable<Subject>
<form asp-action="AddNewSubjects" asp-controller="Teacher" method="post" role="form" class="form-horizontal">
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Number of class</th>
<th>Level</th>
</tr>
</thead>
<tbody>
#if (Model != null)
{
var item = Model.ToList();
#for(int i=0;i<Model.Count();i++)
{
<tr>
<td>#item[i].ID</td>
<td>#item[i].Name</td>
<td>#item[i].ClassNumber</td>
<td>#item[i].Level</td>
</tr>
}
}
</tbody>
</table>
<div class="form-group">
<div class="col-md-offset-2 col-md-5">
<input type="submit" class="btn btn-primary" value="Save all subjects" />
</div>
</div>
</form>
This is my Controller:
private readonly ISubjectService _subjectService;
public TeacherController(ISubjectService subjectService)
{
_subjectService= subjectService;
}
[HttpPost]
public IActionResult AddNewSubjects(IEnumerable<Subject> subjects)
{
var newSubjects= (from p in subjects
where p.State== Status.New
select p);
var result = _subjectService.SaveTeacherSubjects(newSubjects);
return View("ProfesorPages");
}
I have no idea what you're trying to do here. Your form doesn't have any input element except the submit button. Of course you're not seeing anything posted back.
#model IEnumerable<Subject>
<form>
...
<tbody>
#for(int i = 0; i < Model.Count(); i++)
{
<tr>
<td>
<input type="hidden" asp-for="Model[i].ID" />
</td>
<td>
<input type="text" asp-for="Model[i].Name" />
</td>
...
</tr>
}
</tbody>
...
</form>
Why??
Why did you convert your IEnumerable to a list named item? Why not just enumerate your subjects directly?
Why not create a different set of models called ViewModel and pass that to the View, instead of using your model from your database directly on the View?

Select rows and pass data(ID) to next view, MVC5 C#

I have been trying to select multiple rows from my table of data(Generated using EF) and then pass all selected rows to the next view to perform some action. On passing the data to the next view i am getting the following error :
System.NullReferenceException: 'Object reference not set to an instance of an object.'
Temporary local of type 'int[]'> was null.
Any help on how to solve this will be appreciated.
Below is my code:
View:
<div class="row">
<div class="col-md-12">
<!-- Advanced Tables -->
<div class="panel panel-default">
<div class="panel-heading">
#using (Html.BeginForm()) {
<form action="#" method="post">
<label>Search by Company Name:</label> #Html.TextBox("SearchString")
<input type="submit" value="Go" placeholder="Search" style="background-color: #0a9dbd; color: white; border-color: #0a9dbd;">
<label>Search by Card Number:</label> #Html.TextBox("searchCard")
<input type="submit" value="Go" placeholder="Search" style="background-color: #0a9dbd; color: white; border-color: #0a9dbd;">
Export to Excel
</form>
}
</div>
<div class="panel-body">
Add Gift Card
Get Card Balance
Load Cards
<br />
<br />
<div class="table-responsive">
<table class="table table-striped table-bordered table-hover" id="dataTables-example">
<thead>
<tr>
<th>Card ID</th>
<th>Company</th>
<th>Card Number</th>
<th>Card Number 2</th>
<th>Date Created</th>
<th>Card Status</th>
<th>Discount Level ID</th>
<th>Loyalty Level ID</th>
<th>Gift Card Enabled</th>
<th>Loyalty Enabled</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model) {
<tr>
<td><input type="checkbox" name="ids" value="#item.CardID" /></td>
<td>#item.CardID</td>
<td>#item.Customer.CustomerCompanyName</td>
<td>#item.CardNumber</td>
<td>#item.CardNumber2</td>
<td>#item.CardDate</td>
<td>#item.CardStatus</td>
<td>#item.DiscountLevelID</td>
<td>#item.LoyaltyLevelID</td>
<td>#item.GiftCardEnabled</td>
<td>#item.LoyaltyEnabled</td>
<td>
<i class="fa fa-edit "></i> Edit <br />
</td>
</tr>
}
</tbody>
</table>
Page #(Model.PageCount
< Model.PageNumber ? 0 : Model.PageNumber) of #Model.PageCount #Html.PagedListPager(Model, page=> Url.Action("Index", new { page, sortOrder = ViewBag.CurrentSort, currentFilter = ViewBag.CurrentFilter }))
</div>
</div>
</div>
<!--End Advanced Tables -->
</div>
</div>
Controller:
public ActionResult PostCards(int[]ids)
{
var myObject = new Card();
foreach(var id in ids)
{
myObject = db.Cards.Single(o => o.CardID == id);
return RedirectToAction("LoadCards", myObject);
}
return View();
}
public ActionResult LoadCards()
{
return View();
}
I need the selected data to be passed to the LoadCards view.
Let us first look at the NullReference you are getting. The problem here is that no correct index is created to bind the checkboxes to an array. Use a for loop instead of foreach. In MVC/Razor, how do I get the values of multiple checkboxes and pass them all to the controller?
To get the desired behaviour:
change the foreach to a for loop so the correct indices for sending the data will be created.
add a checkbox in each row that lets the user select the rows to submit.
your action should recieve a collection of models for each row. This model always transports the CardId and tells us whether it was selected.
public class SelectedCardModel {
public int CardId { get; set; }
public bool IsSelected {get; set;}
}
In the view:
#using (Html.BeginForm("PostCards", "CustomerView", FormMethod.Post) {
// <table> etc ...
<tbody>
#for (var i = 0; i < Model.Count; i++) {
#{ var item = Model.ElementAt(i); }
<tr>
<td>
#Html.Hidden("CardId[" + i + "]")
#Html.CheckBox("IsSelected[" + i + "]")
</td>
// display other properties of item ...
<td>#item.CardID</td>
// ...
</tr>
}
</tbody>
</table>
<button type="submit">Load Cards</button>
}
Action:
[HttpPost]
public ActionResult PostCards(SelectedCardModel[] selectedCards) {
foreach(var card in selectedCards) {
if (card.IsSelected) {
var selectedId = card.CardId;
// ...
}
}
}

Bind Textbox to model in MVC4

In my MVC application, I have specified two conditions based on the Model.Count to display the values in View.
View
#model IEnumerable<SampleECommerce.Models.DetailsModel>
#using (Html.BeginForm("Details", "Grid", new { UserID = Request.QueryString["UserID"], partnerid = Request.QueryString["Partnerid"] }, FormMethod.Post))
{
if (Model.Count() == 0)
{
#foreach (var item in Model)
{
<table>
<tr>
<td>
#Html.DisplayNameFor(model => model.FirstName)
<input id="FirstName" type="text" class="TextBoxBorder" name="FirstName" value="#item.FirstName" /> // When the Model count is zero, the label and textbox is not displayed.
</td>
</tr>
</table>
}
else
{
#foreach (var item in Model)
{
<table>
<tr>
<td>
#Html.DisplayNameFor(model => model.FirstName)
<input id="MFirstName" type="text" class="TextBoxBorder" name="FirstName" value="#item.FirstName" />
</td>
</tr>
</table>
}
Controller
public ActionResult Details()
{
string userid = Request.QueryString["UserID"];
string partnerid = Request.QueryString["Partnerid"];
con.Open();
SqlCommand cmd = new SqlCommand("select FirstName from Details where UserID = +userid+", con);
SqlDataReader dr = cmd.ExecuteReader();
List<DetailsModel> objmodel = new List<DetailsModel>();
while (dr.Read())
{
objmodel.Add(new DetailsModel()
{
FirstName = dr["First Name"].ToString(),
});
}
dr.Close();
return View(objmodel);
}
When the Model.Count is zero, the label and textbox are not displayed.
I am trying to insert new value to textbox when the model.count is zero based on the userid
I tried to bind the textbox to model all the ways specified in the Link.
1. #Html.TextBoxFor(model => model.FirstName)
Error in FirstName stating "System.Collections.Generic.IEnumerable doesnot find definition for FirstName or no extension method "
2. #Html.TextBox(model=>model.FirstName)
"Error stating Cannot convert Lamba expression to string type"
How to bind and display the textbox value to the model when the model.count is zero.
Any suggestions ??
when the Model.Count is 0, foreach does nothing .
#model IEnumerable<SampleECommerce.Models.DetailsModel>
#using (Html.BeginForm("Details", "Grid", new { UserID = Request.QueryString["UserID"], partnerid = Request.QueryString["Partnerid"] }, FormMethod.Post))
{
<table>
if (Model.Count() == 0)
{
<tr>
<td>
#Html.DisplayNameFor(model => model.FirstName)
<input id="FirstName" type="text" class="TextBoxBorder" name="FirstName" /> // When the Model count is zero, the label and textbox is not displayed.
</td>
</tr>
}
else
{
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayNameFor(model => model.FirstName)
<input id="MFirstName" type="text" class="TextBoxBorder" name="FirstName" value="#item.FirstName" />
</td>
</tr>
}
}
<tr>
<td>
<input type="submit" value="submit" />
</td>
</tr>
</table>
}

Categories

Resources