How to implement pagination in MVC with bootstrap datepicker? - c#

Friends, I have implemented a solution type ASP.NetCore with a project MVC. I have a view in which I used https://github.com/cloudscribe/cloudscribe.Web.Pagination for pagination. **Honestly I took the example and used it. But I don't get the detail about this code example.
The problem that I have now is that, I have to include filters, like datepicker range. So I am using bootstrap datepicker. But the pagination stopped working.
The pagination gets this parameters in querytrings to work: pageNumber, pageSize and query. When I send the request of the filter date, I can get the dates selected in the controller, but the parameters of pagination get in null.
This is an URL example with pagination working fine: http://localhost/pager?query=1&pagesize=10&pageNumber=2
This is an URL when I send the request in the button 'Apply' with dates range, and pagination died without its parameters like 'query': http://localhost/pager?startDate=11/04/2019&endDate=11/11/2019
I suppose I have to send the current querystring in the request too, but I'm not sure, I'm kind of new at this technology. Thanks for any help.
My view →
#using (Html.BeginForm("Details", "Movements", routeValues: new { pageNumber = #Model.UserMovementsResults.PageNumber, pageSize = #Model.UserMovementsResults.PageSize, query = #Model.Query }, FormMethod.Get))
{
<br />
<div style="border: 2px solid #dee2e6;padding: 5px;width: 50%;">
<br />
<div class="input-daterange input-group" id="datepicker">
<span style="font-weight:bold">Date</span> From
#Html.TextBoxFor(model => model.StartDateFilter, "{0:d MMM yyyy}", new
{
id = "StartDateFilter",
#class = "input-sm form-control",
#readonly = "readonly"
})
<span class="input-group-addon"> To </span>
#Html.TextBoxFor(model => model.EndDateFilter, "{0:d MMM yyyy}", new
{
id = "EndDateFilter",
#class = "input-sm form-control",
#readonly = "readonly"
})
</div>
<br />
<input type="submit" value="Apply" class="btn btn-primary" name="Apply" />
</div>
<br />
<br />
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.UserMovementsResults.Data.FirstOrDefault().Date)
</th>
<th>
#Html.DisplayNameFor(model => model.UserMovementsResults.Data.FirstOrDefault().Description)
</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model.UserMovementsResults.Data)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Date)
</td>
<td>
#Html.DisplayFor(modelItem => item.Description)
</td>
</tr>
}
</tbody>
</table>
<div>
<cs-pager cs-paging-pagesize="#Model.UserMovementsResults.PageSize"
cs-paging-pagenumber="#Model.UserMovementsResults.PageNumber"
cs-paging-totalitems="#Model.UserMovementsResults.TotalItems"
cs-pagenumber-param="pageNumber"
cs-show-first-last="true"
cs-suppress-empty-nextprev="true"
cs-remove-nextprev-links="false"
cs-suppress-inactive-firstlast="true"
cs-first-page-text="First"
cs-last-page-text="Last"
cs-pager-li-current-class="active"
cs-pager-li-non-active-class="disabled"
asp-controller="Movements"
asp-route-query="#Model.Query"
asp-route-pagesize="#Model.UserMovementsResults.PageSize"
asp-route-startDateFilter="#Model.StartDateFilter.GetValueOrDefault()"
asp-route-endDateFilter="#Model.EndDateFilter.GetValueOrDefault()"
asp-action="Details" cs-preserve-ambient-querystring="true"></cs-pager>
</div>
}
My Controller (I've tried to set the method HttpGet and HttpPost) →
[HttpGet]
public async Task<IActionResult> Details(int? pageNumber, int? pageSize, int? query, string startDate, string endDate)
{
if (query == null)
{
return NotFound();
}
DateTime startDateFilter = DateTime.Now.StartOfWeek(DayOfWeek.Monday);
DateTime endDateFilter = DateTime.Now.EndOfWeek(DayOfWeek.Monday);
var userMovements = await GetUserMovements(user.Id, pageNumber, pageSize, query, startDateFilter, endDateFilter);
return View(userMovements);
}
}
My ViewModel →
public class UserMovementsViewModel
{
private DateTime? endDateFilter;
public UserMovementsViewModel()
{
UserMovementsResults = new PagedResult<UserMovementsResult>();
}
public string Query { get; set; } = string.Empty;
[Key]
public int Id { get; set; }
public int UserId { get; set; }
public PagedResult<UserMovementsResult> UserMovementsResults { get; set; } = null;
public DateTime? StartDateFilter { get; set; }
public DateTime? EndDateFilter
{
get => endDateFilter;
set
{
if (value != null)
{
endDateFilter = value;
endDateFilter = endDateFilter.Value.AddHours(23).AddMinutes(59).AddSeconds(59);
}
}
}
}
public class UserMovementsResult
{
public DateTime Date { get; set; }
public string Description { get; set; }
}

Here is a simple workaround like below:
1.add the following component in _ViewImports.cshtml:
#using cloudscribe.Web.Pagination
#addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
#addTagHelper "*, cloudscribe.Web.Pagination"
2.Model:
public class UserMovements
{
public string Name { get; set; } = string.Empty;
public DateTime Date { get; set; } = DateTime.UtcNow;
public string Description { get; set; } = string.Empty;
}
public class ViewByDateViewModel
{
public ViewByDateViewModel()
{
UserMovements = new PagedResult<UserMovements>();
}
public PagedResult<UserMovements> UserMovements { get; set; }
public string[] Date { get; set; }
}
3.View(ViewByDate.cshtml):
#using System.Linq
#model ViewByDateViewModel
<form class="form-inline" role="form" asp-controller="Home" asp-action="ViewByDate" method="get" asp-antiforgery="false">
<div class="input-daterange input-group" id="datepicker">
<span style="font-weight:bold">Date</span> From
#Html.TextBox("startDate", null, new
{
id = "startDate",
#class = "input-sm form-control",
})
<span class="input-group-addon"> To </span>
#Html.TextBox("endDate", null, new
{
id = "endDate",
#class = "input-sm form-control",
})
</div>
<input type="submit" value="Browse" class="btn btn-default" />
</form>
#if (Model.UserMovements.Data.Any())
{
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>Name</th>
<th>Date</th>
</tr>
</thead>
<tbody>
#foreach (var product in Model.UserMovements.Data)
{
<tr>
<td>#product.Name</td>
<td>#product.Date</td>
</tr>
}
</tbody>
</table>
<cs-pager cs-paging-pagesize="#Model.UserMovements.PageSize"
cs-paging-pagenumber="#Model.UserMovements.PageNumber"
cs-paging-totalitems="#Model.UserMovements.TotalItems"
cs-pagenumber-param="page"
asp-controller="Home"
asp-action="ViewByDate"
asp-route-categories="#Model.Date.ToCsv()"
asp-route-pagesize="#Model.UserMovements.PageSize"
cs-first-page-text="First"
cs-last-page-text="Last"
cs-previous-page-text="Prev"
cs-next-page-text="Next"></cs-pager>
}
#section Scripts
{
<link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<script>
$(document).ready(function () {
$("#startDate").datepicker({ format: 'dd/mm/yyyy', autoclose: true, todayBtn: 'linked' });
$("#endDate").datepicker({ format: 'dd/mm/yyyy', autoclose: true, todayBtn: 'linked' })
});
</script>
}
4.Controller:
public class HomeController : Controller
{
private const int DefaultPageSize = 10;
private List<UserMovements> allMovements = new List<UserMovements>();
public HomeController()
{
InitializeMovements();
}
private void InitializeMovements()
{
// Create a list of Movements.
for (var i = 0; i < 527; i++)
{
var userMovements = new UserMovements();
userMovements.Name = "UserMovements " + (i + 1);
var categoryIndex = i % 4;
if (categoryIndex > 2)
{
categoryIndex = categoryIndex - 3;
}
userMovements.Date = DateTime.Now.AddDays(i);
allMovements.Add(userMovements);
}
}
public IActionResult ViewByDate(string startDate, string endDate, int? page)
{
string[] dates = { startDate, endDate };
List<UserMovements> filtered;
var currentPageNum = page.HasValue ? page.Value : 1;
var offset = (DefaultPageSize * currentPageNum) - DefaultPageSize;
var model = new ViewByDateViewModel();
model.Date = dates ?? new string[0];
int currentPageIndex = page.HasValue ? page.Value - 1 : 0;
if (startDate == null && endDate == null)
{
filtered = this.allMovements.ToList();
}
else
{
filtered = this.allMovements
.Where(p => p.Date.Date >= DateTime.Parse(startDate) && p.Date.Date <= DateTime.Parse(endDate))
.ToList();
}
model.UserMovements.Data = filtered
.Skip(offset)
.Take(DefaultPageSize)
.ToList();
model.UserMovements.PageNumber = currentPageNum;
model.UserMovements.PageSize = DefaultPageSize;
model.UserMovements.TotalItems = filtered.Count;
return View(model);
}
}
5.Result:
UPDATE:
1.Model:
public class ViewByDateViewModel
{
private DateTime? endDateFilter;
public ViewByDateViewModel()
{
UserMovements = new PagedResult<UserMovements>();
}
public PagedResult<UserMovements> UserMovements { get; set; }
//public string[] Date { get; set; }
public DateTime? StartDateFilter { get; set; }
public DateTime? EndDateFilter
{
get => endDateFilter;
set
{
if (value != null)
{
endDateFilter = value;
endDateFilter = endDateFilter.Value.AddHours(23).AddMinutes(59).AddSeconds(59);
}
}
}
}
2.View:
#using System.Linq
#model ViewByDateViewModel
<form class="form-inline" role="form" asp-controller="Home" asp-action="ViewByDate" method="get" asp-antiforgery="false">
<div class="input-daterange input-group" id="datepicker">
<span style="font-weight:bold">Date</span> From
#Html.TextBox("startDate", null, new
{
id = "startDate",
#class = "input-sm form-control",
})
<span class="input-group-addon"> To </span>
#Html.TextBox("endDate", null, new
{
id = "endDate",
#class = "input-sm form-control",
})
</div>
<input type="submit" value="Browse" class="btn btn-default" />
</form>
#if (Model.UserMovements.Data.Any())
{
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>Name</th>
<th>Date</th>
</tr>
</thead>
<tbody>
#foreach (var product in Model.UserMovements.Data)
{
<tr>
<td>#product.Name</td>
<td>#product.Date</td>
</tr>
}
</tbody>
</table>
<cs-pager cs-paging-pagesize="#Model.UserMovements.PageSize"
cs-paging-pagenumber="#Model.UserMovements.PageNumber"
cs-paging-totalitems="#Model.UserMovements.TotalItems"
cs-pagenumber-param="page"
asp-controller="Home"
asp-action="ViewByDate"
asp-route-pagesize="#Model.UserMovements.PageSize"
asp-route-startDateFilter="#Model.StartDateFilter"
asp-route-endDateFilter="#Model.EndDateFilter"
cs-first-page-text="First"
cs-last-page-text="Last"
cs-previous-page-text="Prev"
cs-next-page-text="Next"></cs-pager>
}
#section Scripts
{
<link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<script>
$(document).ready(function () {
$("#startDate").datepicker({ format: 'dd/mm/yyyy', autoclose: true, todayBtn: 'linked' });
$("#endDate").datepicker({ format: 'dd/mm/yyyy', autoclose: true, todayBtn: 'linked' })
});
</script>
}
3.Controller:
public IActionResult ViewByDate(string startDate, string endDate, int? page)
{
string[] dates = { startDate, endDate };
List<UserMovements> filtered;
var currentPageNum = page.HasValue ? page.Value : 1;
var offset = (DefaultPageSize * currentPageNum) - DefaultPageSize;
var model = new ViewByDateViewModel();
model.StartDateFilter = startDate==null? DateTime.Now:DateTime.Parse(startDate);
model.EndDateFilter = endDate == null ? DateTime.Now : DateTime.Parse(endDate);
int currentPageIndex = page.HasValue ? page.Value - 1 : 0;
if (startDate == null && endDate == null)
{
filtered = this.allMovements.ToList();
}
else
{
filtered = this.allMovements
.Where(p => p.Date.Date >= DateTime.Parse(startDate) && p.Date.Date <= DateTime.Parse(endDate))
.ToList();
}
model.UserMovements.Data = filtered
.Skip(offset)
.Take(DefaultPageSize)
.ToList();
model.UserMovements.PageNumber = currentPageNum;
model.UserMovements.PageSize = DefaultPageSize;
model.UserMovements.TotalItems = filtered.Count;
return View(model);
}
if you want to send by url,url would be like:https://localhost:44367/Home/ViewByDate?startdate=11-14-2019&enddate=11-27-2019

If anyone needs this too, here is how I got it → I was missing the setting of the parameters in the controller with ViewBag. Like this → ViewBag.StartDateFilter = starDate; Otherwise, It was becoming at null always, when I tried to change at another page. I don't why.
I used a hidden field too to save the "query" (in my case this is the user id) because when I sent the request submit in the button, this was losing its value too. What a mess !!
Here is a minified version
View:
<script src="~/lib/bootstrap/bootstrap-datepicker/js/bootstrap-datepicker.js"></script>
<form class="form-inline" role="form" asp-controller="Movements" asp-action="Details" method="get" asp-antiforgery="false" asp-route-query="#ViewBag.Query">
<div>
<div class="input-daterange input-group" id="datepicker">
<span style="font-weight:bold">Date</span> From
#Html.TextBox("startDate", null, new
{
id = "startDate",
#class = "input-sm form-control",
#readonly = "readonly"
})
<span class="input-group-addon"> To </span>
#Html.TextBox("endDate", null, new
{
id = "endDate",
#class = "input-sm form-control",
#readonly = "readonly"
})
</div>
<button asp-route-query="#ViewBag.Query" type="submit" value="Filter" name="Filter">Apply</button>
#Html.Hidden("Query", (object)ViewBag.Query)
</div>
</form>
<br />
<table>
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.UserMovementsResults.Data.FirstOrDefault().Date)
</th>
<th>
#Html.DisplayNameFor(model => model.UserMovementsResults.Data.FirstOrDefault().Description)
</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model.UserMovementsResults.Data)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Date)
</td>
<td>
#Html.DisplayFor(modelItem => item.Description)
</td>
</tr>
}
</tbody>
</table>
<div>
<cs-pager cs-paging-pagesize="#Model.UserMovementsResults.PageSize"
cs-paging-pagenumber="#Model.UserMovementsResults.PageNumber"
cs-paging-totalitems="#Model.UserMovementsResults.TotalItems"
cs-pagenumber-param="pageNumber"
asp-controller="Movements"
asp-action="Details"
asp-route-query="#ViewBag.Query"
asp-route-pagesize="#Model.UserMovementsResults.PageSize"
cs-preserve-ambient-querystring="true"
asp-route-startDate="#ViewBag.StartDateFilter"
asp-route-endDate="#ViewBag.EndDateFilter">
</cs-pager>
</div>
Controller:
[HttpGet]
public async Task<IActionResult> Details(int? pageNumber, UserMovementsViewModel userMovementsViewModel)
{
userMovementsViewModel.StartDateFilter = DateTime.ParseExact(userMovementsViewModel.StartDate, "dd/MM/yyyy", CultureInfo.InvariantCulture);
userMovementsViewModel.EndDateFilter = DateTime.ParseExact(userMovementsViewModel.EndDate, "dd/MM/yyyy", CultureInfo.InvariantCulture).SetEndOfDay();
var userMovements = await GetUserMovements(pageNumber, userMovementsViewModel).ConfigureAwait(true);
ViewBag.StartDateFilter = userMovementsViewModel.StartDateFilter.Value.ToString("dd/MM/yyyy", CultureInfo.InvariantCulture);
ViewBag.EndDateFilter = userMovementsViewModel.EndDateFilter.Value.ToString("dd/MM/yyyy", CultureInfo.InvariantCulture);
ViewBag.Query = userMovementsViewModel.Query;
return View(userMovements);
}
My Class:
public class UserMovementsViewModel
{
public UserMovementsViewModel()
{
UserMovementsResults = new PagedResult<UserMovementsResult>();
}
public string Query { get; set; } = string.Empty;
public PagedResult<UserMovementsResult> UserMovementsResults { get; set; } = null;
public DateTime? StartDateFilter { get; set; }
public DateTime? EndDateFilter { get; set; }
public string StartDate { get; set; }
public string EndDate { get; set; }
}

Related

update session data from ViewModel

here I updated my quantity. how I will use or inject this updated quantity?
[HttpGet]
public ActionResult Details(int? id)
{
ViewBag.product = _db.Spray.ToList();
if (id == null)
{
return NotFound();
}
var hi = _db.Spray.Include(c => c.ProductTypes).FirstOrDefault(c => c.Id == id);
ProductVm product = new ProductVm
{
Name = hi.Name,
Id = hi.Id,
Image=hi.Image,
Image1=hi.Image1,
Quantity = hi.Quantity,
Price = hi.Price,
};
if (product == null)
{
return NotFound();
}
return View(product);
}
[HttpPost]
[ActionName("Details")]
public async Task <IActionResult> ProductDetails(ProductVm pb)
{
List<Spray> sprays = new List<Spray>();
//if (id == null)
//{
// return NotFound();
//}
//var yes = _db.Spray.Include(c => c.ProductTypes).FirstOrDefault(c => c.Id == id);
ProductVm product = new ProductVm()
{
Name = pb.Name,
Id = pb.Id,
Image = pb.Image,
Image1=pb.Image1,
Quantity = pb.Quantity,
Price = pb.Price,
};
if (product == null)
{
return NotFound();
}
sprays = HttpContext.Session.Get<List<Spray>>("sprays");
if (sprays == null)
{
sprays = new List<Spray>();
}
sprays.Add(product);
HttpContext.Session.Set("sprays", sprays);
return RedirectToAction(nameof(Index));
}
[HttpGet]
public IActionResult Cart()
{
List<Spray> sprays = HttpContext.Session.Get<List<Spray>>("sprays");
if (sprays == null)
{
sprays = new List<Spray>();
}
return View(sprays);
}
#model List<Spray>
#{
ViewData["Title"] = "Cart";
}
<div>
<div class="row">
<div class="col-6">
<table class="table table-bordered">
<thead>
<tr>
<th>Image</th>
<th>Name</th>
<th>Quantity</th>
<th>Price</th>
<th>Quantity Update</th>
<th>Total</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>
<img src="~/#item.Image" width="200px" height="150px" />
</td>
<td>#item.Name</td>
<td>#item.Quantity</td>
<td>#item.Price</td>
<td>
<input type="number" asp-for="#item.Quantity" min="0" max="1000" />
</td>
<td>#(item.Price * item.Quantity)</td>
<td>
<a asp-area="Customer" asp-action="Remove" asp-controller="LaptopShow" asp-route-id="#item.Id" class="btn btn-danger">
<i class="fas fa-trash"></i>
</a>
</td>
</tr>
}
</tbody>
</table>
</div>
<div class="col-6">
<div class="text-right">
<h3>Total Amount</h3>
<h3>Grand Total : #Model.Sum(c => c.Price * c.Quantity)</h3>
<a asp-area="Customer" asp-action="Checkout" asp-controller="Order" class="btn btn-info">Process To CheckOut</a>
</div>
</div>
<div>
<a asp-action="Index" asp-controller="SprayShow" class="btn btn-primary">Back To Home</a>
</div>
</div>
</div>
#*<div>
#Html.ActionLink("Edit", "Edit", new { /* id = Model.PrimaryKey */ }) |
<a asp-action="Index">Back to List</a>
</div>*#
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script>
$(function () {
$("input[name='item.Quantity']").change(function () {
//get the new quantity
var newquantity = parseInt($(this).val());
//update the original quantity value
$(this).closest("tr").find("td")[2].innerHTML = newquantity;
//get the price
var price = parseFloat($(this).closest("tr").find("td")[3].innerHTML);
//calculate the total
$(this).closest("tr").find("td")[5].innerHTML = newquantity * price;
//calcule the Grand Total
var grandtotal = 0;
$("tbody").find("tr").each(function (index, item) {
var value = parseFloat($(item).find("td")[5].innerHTML);
grandtotal += value;
});
$(".text-right h3:last").html("Grand Total : " + grandtotal.toString());
});
});
</script>
above code, I change quantity increase and decrease for calculating.but this update value session data could not pick. for that, I am found a problem here to process to checkout problem. I can not found actual quantity data which I updated cart.cshtml.
here my output the updated the quantity using jquery
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using HuddsonBay.Data;
using HuddsonBay.Models;
using HuddsonBay.Utility;
using Microsoft.AspNetCore.Mvc;
namespace HuddsonBay.Areas.Customer.Controllers
{
[Area("Customer")]
public class OrderController : Controller
{
private ApplicationDbContext _db;
public OrderController(ApplicationDbContext db)
{
_db = db;
}
[HttpGet]
public IActionResult Checkout()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Checkout(Order anOrder)
{
//session theke data peck
List<Spray> sprays = HttpContext.Session.Get<List<Spray>>("sprays");
if (sprays != null)
{
for each (var mobile in sprays)
{
OrderDetails orderDetails1 = new OrderDetails();
orderDetails1.ProductId = mobile.Id;
anOrder.OrderDetails.Add(orderDetails1);
}
}
anOrder.OrderNo = GetOrderNo();
_db.Orders.Add(anOrder);
await _db.SaveChangesAsync();
HttpContext.Session.Set("sprays", new List<Spray>());
return RedirectToAction(nameof(Checkout));
}
public String GetOrderNo() //for count order number
{
int rowCount = _db.Orders.ToList().Count() + 1;
return rowCount.ToString("000");
}
}
}
above view, the list of item session data can not pick my updated quantity. how I solved this problem. I am facing problem in order of the value of the quantity.
I am beginner, please anyone help.
Here is a demo to show how to pass List to controller with ajax:
Spray:
public class Spray
{
public int Id { get; set; }
public string Image { get; set; }
public string Name { get; set; }
public int Quantity { get; set; }
public int Price { get; set; }
public int Total { get; set; }
}
Controller:
[HttpGet]
public IActionResult Cart()
{
List < Spray > sprays= new List<Spray> { new Spray { Id = 1, Name = "product1", Price = 10, Quantity = 1, Total = 1,Image="image1.png" }, new Spray { Id = 2, Name = "product2", Price = 20, Quantity = 1, Total = 20,Image="Image2.png" } };
return View(sprays);
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> SendSprays([FromBody]IList<Spray> t) {
return RedirectToAction(nameof(Cart));
}
Cart.cshtml:
<div>
<div class="row">
<div class="col-6">
<table class="table table-bordered" id="myTable">
<thead>
<tr>
<th>Image</th>
<th>Name</th>
<th>Quantity</th>
<th>Price</th>
<th>Quantity Update</th>
<th>Total</th>
<th></th>
<th hidden>Id</th>
<th hidden>ImageValue</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>
<img src="~/#item.Image" width="200px" height="150px" />
</td>
<td>#item.Name</td>
<td>#item.Quantity</td>
<td>#item.Price</td>
<td>
<input type="number" asp-for="#item.Quantity" min="0" max="1000" />
</td>
<td>#(item.Price * item.Quantity)</td>
<td>
<a asp-area="Customer" asp-action="Remove" asp-controller="LaptopShow" asp-route-id="#item.Id" class="btn btn-danger">
<i class="fas fa-trash"></i>
</a>
</td>
<td hidden>#item.Id</td>
<td hidden>#item.Image</td>
</tr>
}
</tbody>
</table>
</div>
<div class="col-6">
<div class="text-right">
<h3>Total Amount</h3>
<h3>Grand Total : #Model.Sum(c => c.Price * c.Quantity)</h3>
<button onclick="checkout()">Process To CheckOut</button>
#*<a asp-action="Checkout" asp-controller="Test" class="btn btn-info">Process To CheckOut</a>*#
</div>
</div>
<div>
<a asp-action="Index" asp-controller="SprayShow" class="btn btn-primary">Back To Home</a>
</div>
</div>
</div>
#*<div>
#Html.ActionLink("Edit", "Edit", new { /* id = Model.PrimaryKey */ }) |
<a asp-action="Index">Back to List</a>
</div>*#
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script>
$(function () {
$("input[name='item.Quantity']").change(function () {
//get the new quantity
var newquantity = parseInt($(this).val());
//update the original quantity value
$(this).closest("tr").find("td")[2].innerHTML = newquantity;
//get the price
var price = parseFloat($(this).closest("tr").find("td")[3].innerHTML);
//calculate the total
$(this).closest("tr").find("td")[5].innerHTML = newquantity * price;
//calcule the Grand Total
var grandtotal = 0;
$("tbody").find("tr").each(function (index, item) {
var value = parseFloat($(item).find("td")[5].innerHTML);
grandtotal += value;
});
$(".text-right h3:last").html("Grand Total : " + grandtotal.toString());
});
});
function checkout() {
var oTable = document.getElementById('myTable');
//gets rows of table
var rowLength = oTable.rows.length;
var sprays = new Array();
//loops through rows
for (i = 1; i < rowLength; i++) {
var tempspray = {};
//gets cells of current row
var oCells = oTable.rows.item(i).cells;
//gets amount of cells of current row
var cellLength = oCells.length;
//tempspray.image = oCells.item(j).
tempspray.Name = oCells.item(1).innerHTML;
tempspray.Quantity = parseInt(oCells.item(2).innerHTML);
tempspray.Price = parseInt(oCells.item(3).innerHTML);
tempspray.Total = parseInt(oCells.item(5).innerHTML);
tempspray.Id = parseInt(oCells.item(7).innerHTML);
tempspray.Image = oCells.item(8).innerHTML;
sprays.push(tempspray);
}
var token = $('input[name="__RequestVerificationToken"]').val();
var t = JSON.stringify(sprays);
$.ajax({
type: "POST",
url: '#(Url.Action("SendSprays", "Test"))',
headers: { "RequestVerificationToken": $('input[name="__RequestVerificationToken"]').val() },
data: t,
contentType: "application/json; charset=utf-8"
});
}
</script>
result:

Model not returning values to controller from dynamically added content?

I have schedule times that can be added dynamically from code behind using Ajax. The user can click an add button and jquery Ajax call should add another set of fields to add a schedule time. From some reason, my model is not returning any values to the controller when I click save.
I've tried using a different model that also includes Date, Start Time and End Time, but the returns no values as well. It seems like the values from the fields are not being posted from the form.
The HTML form
<form asp-action="SetSchedule" asp-controller="Admin" method="post" id="addEventForm">
<table id="scheduleTable">
<thead>
<tr>
<th>Date</th>
<th>Start Time</th>
<th>End Time</th>
<th></th>
</tr>
</thead>
<tbody></tbody>
</table>
<br />
<button id="addScheduleButton" type="button">Add Schedule Time</button>
<button id="savePendingButton" type="submit" style="margin-left:1em" hidden>Save</button>
</form>
Controller:
[HttpPost]
[Authorize(Roles = "Admin")]
public IActionResult SetSchedule(ScheduleViewModel model)
{
_adminManager.SetInterviewSchedule(model);
return RedirectToAction(nameof(ViewSchedule));
}
Model:
public class ScheduleViewModel
{
public List<Schedule> ScheduleItems { get; set; } = new List<Schedule>();
//public InterviewInfoApplicationViewModel InterviewInfo { get; set; } = new InterviewInfoApplicationViewModel();
}
public class Schedule
{
public int Id { get; set; }
public DateTime DateAvailable { get; set; }
[Required]
public DateTime StartTime { get; set; }
[Required]
public DateTime EndTime { get; set; }
public bool IsSelected { get; internal set; }
}
Fields to append on ajax call page:
#model Ambassadors.Managers.ViewModels.Admin.Schedule
#{
string rowClass = "pendingScheduleRow";
}
<tr class="#rowClass" style="margin-top:1em">
<td>
#Html.ValidationMessageFor(x => x.DateAvailable)
<input type="text" asp-for="DateAvailable" class="datepickerInput" />
</td>
<td>
#Html.ValidationMessageFor(x => x.StartTime)
<input type="text" asp-for="StartTime" class="timepickerInput" />
</td>
<td>
#Html.ValidationMessageFor(x => x.EndTime)
<input type="text" asp-for="EndTime" class="timepickerInput" />
</td>
<td>
<a class="tooltip deletePendingSchedule" title="Remove Schedule Time" style="cursor:pointer">
<span class="wdn-icon-cancel" aria-hidden="true"></span><span class="wdn-text-hidden">cancel icon</span>
</a>
</td>
</tr>
Script:
require(['jquery', 'jqueryui'], function ($, jqueryui) {
$(function () {
$('body').on('focus', ".datepickerInput", function () {
$(this).datepicker({
controlType: "select",
});
});
$('body').on('focus', ".timepickerInput", function () {
$(this).timepicker({
timeFormat: "hh:mm tt",
interval: 5,
dropdown: true,
scrollbar: true
});
});
$("#addScheduleButton").click(function () {
var nextIndex = $(".pendingScheduleRow").length;
$.ajax({
url: "/Admin/AddScheduleItem",
type: 'POST',
data: {
index: nextIndex
},
success: function (results) {
$("table#scheduleTable tbody").append(results);
$("#savePendingButton").show();
}
});
});
$("#scheduleTable").on("click", ".deletePendingSchedule", function () {
var closestRow = $(this).closest("tr");
$(closestRow).hide();
var visibleRows = $(".pendingScheduleRow:visible").length;
if (visibleRows === 0) {
$("#savePendingButton").hide();
}
});
});
});
Model should return DateAvailable, StartTime and EndTimes to the controller.
Your action receives model type of ScheduleViewModel who has a property of List<Schedule> while your view asp-for="DateAvailable" neither bind to ScheduleViewModel nor bind to List<Schedule>.
Refer to my below demo:
1.AddScheduleItem action to return index to partial view
public IActionResult AddScheduleItem(string index)
{
var myViewData = new ViewDataDictionary(new Microsoft.AspNetCore.Mvc.ModelBinding.EmptyModelMetadataProvider(), new Microsoft.AspNetCore.Mvc.ModelBinding.ModelStateDictionary())
{
{ "index", index }
};
PartialViewResult result = new PartialViewResult()
{
ViewName = "YourPartialViewName",
ViewData = myViewData,
};
return result;
}
2.YourPartailView:
#model ScheduleViewModel
#{
string rowClass = "pendingScheduleRow";
int index = Int32.Parse(#ViewData["index"].ToString());
}
<tr class="#rowClass" style="margin-top:1em">
<td>
#Html.ValidationMessageFor(x => x.ScheduleItems[index].DateAvailable)
<input asp-for="ScheduleItems[index].DateAvailable" class="datepickerInput" />
</td>
<td>
#Html.ValidationMessageFor(x => x.ScheduleItems[index].StartTime)
<input asp-for="ScheduleItems[index].StartTime" class="timepickerInput" />
</td>
<td>
#Html.ValidationMessageFor(x => x.ScheduleItems[index].EndTime)
<input asp-for="ScheduleItems[index].EndTime" class="timepickerInput" />
</td>
<td>
<a class="tooltip deletePendingSchedule" title="Remove Schedule Time" style="cursor:pointer">
<span class="wdn-icon-cancel" aria-hidden="true"></span><span class="wdn-text-hidden">cancel icon</span>
</a>
</td>
</tr>
#{ await Html.RenderPartialAsync("_ValidationScriptsPartial");}

ASP NET MVC - Form in view

i have a problem in my asp.net view. I'v got a foreach loop, and i can't put my first iteration into my form.
That's the code:
<div id="#item.Name" class="tab-pane fade in active">
<div class="row">
#{int i = 0;}
#foreach (var prod in item.Products.Where(p => p.Type_Id == item.Id && p.IsDeleted != true))
{
using (Html.BeginForm("AddOrderRow", "Orders", new { enctype = "multipart/form-data", #class = "form-inline" }))
{
<input type="hidden" value="#ViewBag.orderId" name="Order_Id" />
<input type="hidden" value="#prod.Id" name="ProductID" />
<input type="hidden" value="#prod.Price" name="Price" />
<div class="col-sm-3" style="padding-bottom:20px">
<div align="center">
<button style="background-color:transparent; border-color:transparent">
<img class="img-responsive" src='#VirtualPathUtility.ToAbsolute(String.Format("{0}/{1}", System.Configuration.ConfigurationManager.AppSettings["ProdUploadPath"], prod.Image))' style="max-height: 100px" data-toggle="tooltip" title="#prod.Name">
</button>
</div>
</div>
if (i % 4 == 3)
{
#:</div><div class="row">
}
i++;
}
}
</div>
</div>
And that's how it look:
As you can see, only first div into first row is out of my form.
my suggest if you want save list, use save list not iteration form
example controller here;s the one when i learn mvc hahaha
public ActionResult Create(int? area, string now, string search, string message)
{
ViewBag.Area = new SelectList(CoreList.GetDropdown("UnitArea"), "DropdownId", "Value", area);
ViewBag.SelectedArea = area;
var newdate = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day);
IFormatProvider culture = new CultureInfo(CultureInfo.CurrentCulture.Name, true);
if (!string.IsNullOrWhiteSpace(now))
{
DateTime.TryParse(now, culture, DateTimeStyles.AssumeLocal, out newdate);
}
ViewBag.dateFilter = newdate.ToString(CultureInfo
.GetCultureInfo(CultureInfo.CurrentCulture.Name)
.DateTimeFormat.ShortDatePattern);
ViewBag.Search = search;
var attendances = (from p in db.MstUnitDriverPairings
join x in db.TrnAttendanceUnits
.Where(o => o.PresentDate.Value.Year == newdate.Year &&
o.PresentDate.Value.Month == newdate.Month &&
o.PresentDate.Value.Day == newdate.Day)
on p.UnitId equals x.UnitId into j1
from x in j1.DefaultIfEmpty()
join v in db.TrnAttendanceUnits.OrderByDescending(o => o.PresentDate).Where(o => o.ClockOut == null && o.PresentDate < newdate)
on p.UnitId equals v.UnitId into jd1
from v in jd1.DefaultIfEmpty()
join y in db.TrnAttendanceDrivers.Where(o => o.PresentDate == newdate)
on p.DriverId equals y.DriverId into j2
from y in j2.DefaultIfEmpty()
join z in db.TrnAttendanceDrivers.OrderByDescending(o => o.PresentDate).Where(o => o.ClockOut == null && o.PresentDate < newdate)
on p.DriverId equals z.DriverId into jd2
from z in jd2.DefaultIfEmpty()
where (area == null ? true : p.MstUnits.UnitArea == area)
&& (string.IsNullOrEmpty(search) ? true : p.MstDrivers.DriverName.ToLower().Contains(search.ToLower())
|| p.MstUnits.PoliceNo.ToLower().Contains(search.ToLower()))
&& p.MstUnits.UnitPrimary == true
select new Attendance
{
DriverId = p.DriverId,
DriverName = p.MstDrivers.DriverName,
DriverIn = y.ClockIn == null ? false : true,
DriverOut = y.ClockOut == null ? false : true,
DriverInDate = y.ClockIn,
DriverInDateBefore = z.ClockIn,
DriverOutDate = y.ClockOut,
DriverOutDateBefore = z.ClockOut,
UnitId = p.UnitId,
PoliceNumber = p.MstUnits.PoliceNo,
UnitIn = x.ClockIn == null? false : true,
UnitOut = x.ClockOut == null ? false : true,
UnitInDate = x.ClockIn,
UnitInDateBefore = v.ClockIn,
UnitOutDate = x.ClockOut,
UnitOutDateBefore = v.ClockOut
}).ToList();
return View(attendances);
}
[HttpPost]
public ActionResult AttendanceSave(List<Attendance> Models, string presentDate, int? area, string search)
{
string message = string.Empty;
var newdate = new DateTime();
IFormatProvider culture = new CultureInfo(CultureInfo.CurrentCulture.Name, true);
if (DateTime.TryParse(presentDate, culture, DateTimeStyles.AssumeLocal, out newdate))
{
foreach (var item in Models)
{
TrnAttendanceDriver trnAttendanceDriver = db.TrnAttendanceDrivers.FirstOrDefault(o => o.PresentDate == newdate && o.DriverId == item.DriverId);
TrnAttendanceUnit trnAttendanceUnit = db.TrnAttendanceUnits.FirstOrDefault(o => o.PresentDate == newdate && o.UnitId == item.UnitId);
if (trnAttendanceDriver != null)
{
if (item.DriverIn && item.DriverInDate != null) trnAttendanceDriver.ClockIn = item.DriverInDate;
if (item.DriverOut && item.DriverOutDate != null)
{
trnAttendanceDriver.ClockOut = item.DriverOutDate;
trnAttendanceDriver.Status = false;
}
}
else
{
if (item.DriverIn)
{
var newDriverAttendance = new TrnAttendanceDriver();
newDriverAttendance.DriverId = item.DriverId;
newDriverAttendance.ClockIn = item.DriverInDate;
newDriverAttendance.PresentDate = newdate;
newDriverAttendance.Status = true;
db.TrnAttendanceDrivers.Add(newDriverAttendance);
}
}
if (trnAttendanceUnit != null)
{
if (item.UnitIn && item.UnitInDate != null) trnAttendanceUnit.ClockIn = item.UnitInDate;
if (item.UnitOut && item.UnitOutDate != null)
{
trnAttendanceUnit.ClockOut = item.UnitOutDate;
trnAttendanceUnit.Status = false;
}
}
else
{
if (item.UnitIn)
{
var newUnitAttendance = new TrnAttendanceUnit();
newUnitAttendance.UnitId = item.UnitId;
newUnitAttendance.ClockIn = item.UnitInDate;
newUnitAttendance.PresentDate = newdate;
newUnitAttendance.Status = true;
db.TrnAttendanceUnits.Add(newUnitAttendance);
}
}
}
}
try
{
db.SaveChanges();
}
catch //(Exception ex)
{
throw;
}
return RedirectToAction("Index","Transaction/Attendance", new {area, search, message, now = presentDate });
}
here's the model
public class Attendance
{
public int DriverId { get; set; }
[Display(Name = "Name")]
public string DriverName { get; set; }
[Display(Name = "Driver In")]
public bool DriverIn { get; set; }
[DataType(DataType.DateTime)]
public DateTime? DriverInDate { get; set; }
[DataType(DataType.DateTime)]
public DateTime? DriverOutDateBefore { get; set; }
[DataType(DataType.DateTime)]
public DateTime? DriverInDateBefore { get; set; }
[Display(Name = "Driver Out")]
public bool DriverOut { get; set; }
[DataType(DataType.DateTime)]
public DateTime? DriverOutDate { get; set; }
public int UnitId { get; set; }
[Display(Name = "Police Number")]
public string PoliceNumber { get; set; }
[Display(Name = "Unit In")]
public bool UnitIn { get; set; }
[DataType(DataType.DateTime)]
public DateTime? UnitInDate { get; set; }
[DataType(DataType.DateTime)]
public DateTime? UnitOutDateBefore { get; set; }
[DataType(DataType.DateTime)]
public DateTime? UnitInDateBefore { get; set; }
[Display(Name = "Unit Out")]
public bool UnitOut { get; set; }
[DataType(DataType.DateTime)]
public DateTime? UnitOutDate { get; set; }
}
and here's view
#model List<Solution.Web.Areas.Transaction.Models.Attendance>
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<nav class="navbar navbar-white" role="navigation">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#nav2">
<span class="sr-only">Toggle</span>
<span class="glyphicon glyphicon-search"></span>
</button>
<a class="navbar-brand">Search</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="nav2">
<form class="navbar-form navbar-right" role="search">
<div class="form-group">
#Html.DropDownList("Area", string.Empty)
</div>
<div class="form-group">
<input type="text" name="now" id="dateFilter" class="form-control datepicker" value="#ViewBag.dateFilter" />
</div>
<div class="form-group">
<input type="text" name="Search" class="form-control" value="#ViewBag.Search" placeholder="Search" />
</div>
<button type="submit" class="btn btn-primary">
<span class="glyphicon glyphicon-search"></span>
</button>
</form>
</div>
<!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>
#using (Html.BeginForm("AttendanceSave", "Attendance", FormMethod.Post))
{
<input type="hidden" name="presentDate" value="#ViewBag.dateFilter" />
<input type="hidden" name="area" value="#ViewBag.SelectedArea" />
<input type="hidden" name="search" value="#ViewBag.Search" />
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Attendance</h3>
</div>
<div class="table-responsive">
<table class="table table-striped">
<tr>
<th colspan="3">
Driver
</th>
<th colspan="3">
Unit
</th>
</tr>
<tr>
<th>
Name
</th>
<th>
In
#Html.CheckBox("drivercheckInHead")
</th>
<th>
Out
#Html.CheckBox("drivercheckOutHead")
</th>
<th>
Police Number
</th>
<th>
In
#Html.CheckBox("unitcheckInHead")
</th>
<th>
Out
#Html.CheckBox("unitcheckOutHead")
</th>
</tr>
#for (int i = 0; i < Model.Count(); i++)
{
<tr>
#Html.Hidden("Models[" + i + "].DriverId", Model[i].DriverId)
#Html.Hidden("Models[" + i + "].UnitId", Model[i].UnitId)
<td>
#Html.DisplayFor(m => m[i].DriverName)
</td>
<td>
#if (Model[i].DriverIn && Model[i].DriverOut)
{
#Html.Hidden("Models[" + i + "].DriverIn", Model[i].DriverIn)
#Html.Hidden("Models[" + i + "].DriverInDate", Model[i].DriverInDate)
#Model[i].DriverInDate.Value.ToString("dd MMMM yyyy HH:mm")
}
else
{
if (Model[i].DriverOutDateBefore == null && Model[i].DriverInDateBefore != null)
{
<label class="label label-danger">
#Model[i].DriverInDateBefore.Value.ToString("dd MMMM yyyy HH:mm")
</label>
}
else
{
<div class="input-group input-group-sm">
<span class="input-group-addon">
#Html.CheckBox("Models[" + i + "].DriverIn", Model[i].DriverIn, new { #class = "drivercheckIn" })
</span>
#Html.TextBox("Models[" + i + "].DriverInDate", Model[i].DriverInDate, new { #class = "datetimepicker drivercheckInDate" })
</div>
}
}
</td>
<td>
#if (Model[i].DriverIn && Model[i].DriverOut)
{
#Html.Hidden("Models[" + i + "].DriverOut", Model[i].DriverOut)
#Html.Hidden("Models[" + i + "].DriverOutDate", Model[i].DriverOutDate)
#Model[i].DriverOutDate.Value.ToString("dd MMMM yyyy HH:mm")
}
else
{
if (Model[i].DriverIn)
{
<div class="input-group input-group-sm">
<span class="input-group-addon">
#Html.CheckBox("Models[" + i + "].DriverOut", Model[i].DriverOut, new { #class = "drivercheckOut" })
</span>
#Html.TextBox("Models[" + i + "].DriverOutDate", Model[i].DriverOutDate, new { #class = "datetimepicker drivercheckOutDate" })
</div>
}
else
{
<span class="label label-info">Need driver in</span>
}
}
</td>
<td>
#Html.DisplayFor(m => m[i].PoliceNumber)
</td>
<td>
#if (Model[i].UnitIn && Model[i].UnitOut)
{
#Html.Hidden("Models[" + i + "].UnitIn", Model[i].UnitIn)
#Html.Hidden("Models[" + i + "].UnitIn", Model[i].UnitInDate)
#Model[i].UnitInDate.Value.ToString("dd MMMM yyyy HH:mm")
}
else
{
if (Model[i].UnitOutDateBefore == null && Model[i].UnitInDateBefore != null)
{
<label class="label label-danger">
#Model[i].UnitInDateBefore.Value.ToString("dd MMMM yyyy HH:mm")
</label>
}
else
{
<div class="input-group input-group-sm">
<span class="input-group-addon">
#Html.CheckBox("Models[" + i + "].UnitIn", Model[i].UnitIn, new { #class = "unitcheckIn" })
</span>
#Html.TextBox("Models[" + i + "].UnitInDate", Model[i].UnitInDate, new { #class = "datetimepicker unitcheckInDate" })
</div>
}
}
</td>
<td>
#if (Model[i].UnitIn && Model[i].UnitOut)
{
#Html.Hidden("Models[" + i + "].UnitOut", Model[i].UnitOut)
#Html.Hidden("Models[" + i + "].UnitOutDate", Model[i].UnitOutDate)
#Model[i].UnitOutDate.Value.ToString("dd MMMM yyyy HH:mm")
}
else
{
if (Model[i].UnitIn)
{
<div class="input-group input-group-sm">
<span class="input-group-addon">
#Html.CheckBox("Models[" + i + "].UnitOut", Model[i].UnitOut, new { #class = "unitcheckOut" })
</span>
#Html.TextBox("Models[" + i + "].UnitOutDate", Model[i].UnitOutDate, new { #class = "datetimepicker unitcheckOutDate" })
</div>
}
else
{
<span class="label label-info">Need unit in</span>
}
}
</td>
</tr>
}
</table>
</div>
#if (Model.Count() > 0)
{
<div class="panel-footer">
<button type="submit" class="btn btn-primary">
<span class="glyphicon glyphicon-ok"> Submit</span>
</button>
</div>
}
</div>
}
hope this helps, sorry for my bad codes, hehehe

Pass dynamic model to controller

I have table which is filled with some data, when I click "addTemplate" in my controller I don't get any data from table.
Here is my index.cshtml
#model ReportGenerator.WebUI.Models.FieldViewModel
#{
var list = #Model.IEnumerableField.GroupBy(item => item.TemplateName).ToList();
}
#using (Html.BeginForm("addTemplate", "TemplateField", FormMethod.Post))
{
<div class="form-group">
<div class="input-group">
<label class="label label-default">Nazwa szablonu*</label>
#Html.TextBoxFor(m => m.field.TemplateName, new { #class = "form-control" })
<br /><br />
</div>
</div>
<table id="sort" class="table">
<thead>
<tr>
<th>Nazwa kolumny z BD*</th>
<th>Długość rekordu*</th>
<th>Nazwa kolumny wyświetlana</th>
<th>Format*</th>
</tr>
</thead>
<tbody id="tblsort">
#for (var i = 0; i < Model.listOfFormats(Model.field.TemplateName).ColumnNamesDB.Count; i++)
{
<tr>
<td>#Html.TextBoxFor(m => Model.listOfFormats(Model.field.TemplateName).ColumnNamesDB[i], new { #class = "form-control" })</td>
<td>#Html.TextBoxFor(m => Model.listOfFormats(Model.field.TemplateName).LengthColumns[i], new { #class = "form-control" })</td>
<td>#Html.TextBoxFor(m => Model.listOfFormats(Model.field.TemplateName).ColumnNamesUser[i], new { #class = "form-control" })</td>
<td>#Html.DropDownListFor(m => Model.listOfFormats(Model.field.TemplateName).Formats[i], new SelectList(Model.formatFieldValues, "Value", "Text"), Model.listOfFormats(Model.field.TemplateName).Formats[i], new { #class = "form-control" })</td>
</tr>
}
</tbody>
</table>
<div id="hiddenHtml" style="display:none;">
#Html.DropDownList("FormatFieldName", new SelectList(Model.formatFieldValues, "Value", "Text"), "Domyślny", new { #class = "form-control" })
</div>
<button class="btn btn-success" type="button" id="addRow" style="float: right;"><span class="glyphicon glyphicon-plus" id="addRow"></span></button>
<button class="btn btn-success" id="save" style="float: left;">Zapisz</button>
<br /><br /><br />
<div>
<p style="float: right;">* - Pole oznaczone gwiązdką są obowiązkowe!</p>
</div>
<br /> <br />
#Html.ValidationSummary()
<h1 style="color:#ViewBag.color">#ViewBag.Info</h1>
}
Here is my model
public class FieldViewModel
{
public TemplateField field { get; set; }
public IEnumerable<TemplateField> IEnumerableField;
public Fields fieldObj {get;set;}
public Fields listOfFormats(string nameTemplate)
{
Fields obj = new Fields();
var items = IEnumerableField.Where(i => i.TemplateName == nameTemplate).ToList();
if (items != null)
{
foreach (var x in items)
{
obj.ColumnNamesDB.Add(x.ColumnNameDB);
obj.Formats.Add(x.Format);
obj.LengthColumns.Add(x.Length.ToString());
obj.ColumnNamesUser.Add(x.ColumnNameUser);
}
}
return obj;
}
}
and finally my controller method
public ActionResult addTemplate(FieldViewModel model)
{
return ? // model is empty, there is nothing...
}
I think that I made some mistake in Model, can someone look at this?
Thanks for any help!
EDIT:
Here is Fields class:
public class Fields
{
public List<string> ColumnNamesDB = new List<string>();
public List<string> LengthColumns = new List<string>();
public List<string> Formats = new List<string>();
public List<string> ColumnNamesUser = new List<string>();
}
and TemplateField cass
public class TemplateField
{
[Key]
public int FieldId { get; set; }
[Required(ErrorMessage = "Proszę podać nazwę kolumny z bazy danych.")]
public string ColumnNameDB { get; set; }
[Required(ErrorMessage = "Proszę podać długość rekordu.")]
public int Length { get; set; }
public string Format { get; set; }
[Required(ErrorMessage = "Proszę podać nazwę szablonu.")]
public string TemplateName { get; set; }
[Required(ErrorMessage = "Proszę podać nazwę kolumny jaka będzie wyświetlana.")]
public string ColumnNameUser { get; set; }
}
EDIT
Ok I have made a lot of miastakes here so this question don't have an answer I think.

MVC Enum Model Binding in For Loop

I have an MVC 5 app where I am using a for loop so I can bind a collection when passing back to the controller. This works fine for all my properties except for the one that is based on a DropDownFor type.
The problem is the name of the property is not getting set to "product.[0].TypeOfSubscription.
I have tried 3 different ways: The first 2 method end up with a name of [0].TypeOfSubscription and the 3rd one does have the correct name product[0].TypeOfSubscription but there is no binding occuring when I pass it back to the controller.
I think the problem is that the 3rd option is binding but because it is hidden it is not getting the selected value assigned.
#Html.EnumDropDownListFor(modelItem => Model[i].TypeOfSubscription)
#Html.EnumDropDownListFor(modelItem => Model[i].TypeOfSubscription,
new { name = "product[" + #i + "].TypeOfSubscription"})
#Html.Hidden("product[" + #i + "].TypeOfSubscription",
Model[i].TypeOfSubscription)
Model
public class VmStoreProducts
{
public VmStoreProducts()
{
NoOfUsers = 1;
}
public enum SubscriptionType
{
Monthly,
Annual
}
public int MojitoProductId { get; set; }
[Display(Name = "Category")]
public string ProductCategory { get; set; }
public virtual string Name { get; set; }
public string Description { get; set; }
[Display(Name = "Image")]
public byte[] ImageData { get; set; }
[Display(Name = "Type of Subscription")]
public SubscriptionType TypeOfSubscription { get; set; }
public decimal Price { get; set; }
[Display(Name = "No. of Users")]
public int NoOfUsers { get; set; }
[Display(Name = "Total Price")]
[DisplayFormat(DataFormatString = "{0:C}")]
public decimal TotalPrice { get; set; }
}
For Loop - View
#model PagedList.IPagedList<VmStoreProducts>
#using Mojito.Domain
#using PagedList.Mvc;
<link href="~/Content/PagedList.css" rel="stylesheet" type="text/css" />
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Mojito Products</h2>
<div class="col-md-9"></div>
<div class="col-md-3">
#using (Html.BeginForm("Index", "MojitoProducts", FormMethod.Get))
{
<p>
#Html.TextBox("SearchString", ViewBag.CurrentFilter as string)
<input type="submit" value="Search" />
</p>
}
</div>
#using (Html.BeginForm("AddToCart", "ShoppingCart", FormMethod.Post))
{
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.FirstOrDefault().ImageData)
</th>
<th>
#Html.ActionLink("Category", "Index", new { sortOrder = ViewBag.SortByCategory, currentFilter = ViewBag.CurrentFilter })
</th>
<th>
#Html.ActionLink("Product", "Index", new { sortOrder = ViewBag.SortByProduct, currentFilter = ViewBag.CurrentFilter })
</th>
<th>
#Html.DisplayNameFor(model => model.FirstOrDefault().Description)
</th>
<th>
#Html.DisplayNameFor(model => model.FirstOrDefault().TypeOfSubscription)
</th>
<th>
#Html.ActionLink("Price", "Index", new { sortOrder = ViewBag.SortByPrice, currentFilter = ViewBag.CurrentFilter })
</th>
<th>
#Html.DisplayNameFor(model => model.FirstOrDefault().NoOfUsers)
</th>
<th>
#Html.DisplayNameFor(model => model.FirstOrDefault().TotalPrice)
</th>
<th></th>
</tr>
#for (int i = 0; i < Model.Count; i++)
{
<tr>
<td>
#if (Model[i].ImageData != null)
{
<div class="pull-left" style="margin-right: 10px">
<img class="img-thumbnail" width="75" height="75"
src="#Url.Action("GetImage", "MojitoProducts",
new { Model[i].MojitoProductId })" />
</div>
}
</td>
<td>
#Html.DisplayFor(modelItem => Model[i].ProductCategory)
</td>
<td>
#Html.TextBox("product[" + #i + "].Name",
Model[i].Name, new { #readonly = "readonly" })
</td>
<td>
#Html.DisplayFor(modelItem => Model[i].Description)
</td>
<td>
#Html.EnumDropDownListFor(modelItem => Model[i].TypeOfSubscription)
#Html.EnumDropDownListFor(modelItem => Model[i].TypeOfSubscription,
new { name = "product[" + #i + "].TypeOfSubscription"})
#Html.TextBox("product[" + #i + "].TypeOfSubscription",
Model[i].TypeOfSubscription, new { hidden=true })
</td>
<td>
#Html.TextBox("product[" + #i + "].Price",
Model[i].Price, new { #readonly = "readonly", style = "width:50px" })
</td>
<td>
#Html.TextBox("product[" + #i + "].NoOfUsers",
Model[i].NoOfUsers, new { type = "number", min = "0", style = "width:50px" })
</td>
<td>
#Html.TextBox("product[" + #i + "].TotalPrice",
Model[i].TotalPrice, new { style = "width:50px" })
</td>
<td>
<div class="pull-right">
#if (Request.Url != null)
{
#Html.Hidden("product[" + #i + "].MojitoProductId",
Model[i].MojitoProductId)
#Html.Hidden("returnUrl", Request.Url.PathAndQuery)
}
</div>
</td>
</tr>
}
<tr>
<td colspan="6">
<div class="pull-right">
<input type="submit" class="btn btn-success" value="Add to cart" />
</div>
</td>
</tr>
</table>
}
Controller Method
public ActionResult AddToCart(List<VmStoreProducts> product, string returnUrl)
{
ShoppingCart cartObjects = (Session["CartObjects"] as ShoppingCart) ?? new ShoppingCart();
Session["CartObjects"] = cartObjects;
foreach (var item in product)
{
if (item.NoOfUsers > 0)
{
cartObjects.AddItem(item);
}
}
return RedirectToAction("Index", new { returnUrl });
}
Move the definition of the enum outside the VmStoreProducts class
public enum SubscriptionType
{
Monthly,
Annual
}
public class VmStoreProducts
{
public VmStoreProducts()
{
NoOfUsers = 1;
}
public int MojitoProductId { get; set; }
....
}
The for loop will name the selects
[0].TypeOfSubscription
[1].TypeOfSubscription
....
which will correctly bind on postback (assuming your action method is public ActionResult AddToCart(IEnumerable<VmStoreProducts> products) {...
Also, do not use
#Html.TextBox("product[" + #i + "].Name", Model[i].Name, new { #readonly = "readonly" })
Since you already using a DisplayFor for the same property a hidden input seems more appropriate, so
#Html.HiddenFor(m => m[i].Name)
or if you want to display it twice
#Html.TextBoxFor(m => m[i].Name, new { #readonly = "readonly" })
This applies to the other properties as well
Try using a textbox and hide it to persist the value or use another 'data- property
In case of DropDownListFor, when data is posted back to controller, selected value get lost, so we need to have a hidden textbox to keep the selected value

Categories

Resources