Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary.EnsureCompatible(object value) - asp.net-core-mvc

This is the error I get; please tell me how I can solve it:
InvalidOperationException: the model item passed into the ViewDataDictionary is of type 'System.Collections.Generic.List1[AgricultureFarming.Models.AddToCart]', but this ViewDataDictionary instance requires a model item of type 'System.Collections.Generic.IEnumerable1[AgricultureFarming.Models.Order]'}
My Index View Page code I want to display product in orders index page from Addtocart model
#model IEnumerable<AgricultureFarming.Models.Order>
#{
ViewData["Title"] = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h1>Index</h1>
<p>
<a asp-action="Create">Create New</a>
</p>
<div class="container">
<div class="row">
<div>
<table class="table">
<tbody>
#foreach (var item in Model)
{
<tr>
<td>
<img src="~/Images/#item.AddToCarts.Products.Image_path" class="img-fluid" style="height:50px;width:85px;" asp-append-version="true" />
</td>
<td>
<b>
#Html.DisplayFor(modelItem => item.AddToCarts.Products.Product_Name)
</b>
</td>
<td>
1 KG = #Html.DisplayFor(modelItem => item.AddToCarts.Products.Price)
</td>
<td>
#Html.DisplayFor(modelItem => item.AddToCarts.Quantity)
</td>
<td>
#(item.AddToCarts.Quantity* item.AddToCarts.Products.Price)
</td>
</tr>
}
</tbody>
<tfoot>
<tr>
<td></td>
<td></td>
<td></td>
<td><b>Sub Total</b></td>
<td>#Model.Sum(i => i.AddToCarts.Quantity * i.AddToCarts.Products.Price) TK</td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td><b>Delivery Charge</b></td>
<td><text id="DeliveryCharge"></text></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td><b>Total Amount</b></td>
<td><text id="Total">#Model.Sum(i => i.AddToCarts.Quantity * i.AddToCarts.Products.Price) TK</text></td>
</tr>
</tfoot>
</table>
</div>
<div class="form-group col-md-3">
<div>
<select id="CountryList" class="form-control" asp-items="ViewBag.CountryList"></select>
</div>
<div class="form-group col-md-3"></div>
<div>
<select id="CityList" class="form-control"></select>
<br />
<text>Address:</text>
<br />
<textarea class="form-control"></textarea>
</div>
<div>
<text>Zip Code:</text>
<br />
<input type="text" name="name" value="" class="form-control"/>
</div>
</div>
</div>
</div>
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="container">
<div class="row">
<div class="form-group col-md-3 align-self-start">
<select id="CountryList" class="form-control" asp-items="ViewBag.CountryList"></select>
</div>
<div class="form-group col-md-3">
<select id="CityList" class="form-control"></select>
</div>
</div>
</div>
My model class:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace AgricultureFarming.Models
{
public class Order
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public string Id { get; set; }
[Display(Name = "Delivery Charge")]
public int DeliveryChargesId { get; set; }
[Required]
public string UserId { get; set; }
[Display(Name = "Item")]
public string AddToCartsId { get; set; }
[Required]
public string DeliveryAddress { get; set; }
[Required]
[Display(Name = "Total Price")]
[Column(TypeName = "decimal(10,2)")]
public decimal TotalAmount { get; set; }
[Required]
public DateTime OrderDate { get; set; }
public DeliveryCharge DeliveryCharges { get; set; }
public AddToCart AddToCarts { get; set; }
}
}

Your Index action returns the AddToCart collection type, so your view should use #model AgricultureFarming.Models.AddToCart to receive.
To solve this issue, change the index view code as follow:
#model IEnumerable<AgricultureFarming.Models.AddToCart>
#{
ViewData["Title"] = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h1>Index</h1>
<p>
<a asp-action="Create">Create New</a>
</p>
<div class="container">
<div class="row">
<div>
<table class="table">
<tbody>
#foreach (var item in Model)
{
<tr>
<td>
<img src="~/pics/#item.Products.Image_path" class="img-fluid" style="height:50px;width:85px;" asp-append-version="true" />
</td>
<td>
<b>
#Html.DisplayFor(modelItem => item.Products.Product_Name)
</b>
</td>
<td>
1 KG = #Html.DisplayFor(modelItem => item.Products.Price)
</td>
<td>
#Html.DisplayFor(modelItem => item.Quantity)
</td>
<td>
#(item.Quantity* item.Products.Price)
</td>
</tr>
}
</tbody>
<tfoot>
<tr>
<td></td>
<td></td>
<td></td>
<td><b>Sub Total</b></td>
<td>#Model.Sum(i => i.Quantity * i.Products.Price) TK</td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td><b>Delivery Charge</b></td>
<td><text id="DeliveryCharge"></text></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td><b>Total Amount</b></td>
<td><text id="Total">#Model.Sum(i => i.Quantity * i.Products.Price) TK</text></td>
</tr>
</tfoot>
</table>
</div>
<div class="form-group col-md-3">
<div>
<select id="CountryList" class="form-control" asp-items="ViewBag.CountryList"></select>
</div>
<div class="form-group col-md-3"></div>
<div>
<select id="CityList" class="form-control"></select>
<br />
<text>Address:</text>
<br />
<textarea class="form-control"></textarea>
</div>
<div>
<text>Zip Code:</text>
<br />
<input type="text" name="name" value="" class="form-control" />
</div>
</div>
</div>
</div>
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="container">
<div class="row">
<div class="form-group col-md-3 align-self-start">
<select id="CountryList" class="form-control" asp-items="ViewBag.CountryList"></select>
</div>
<div class="form-group col-md-3">
<select id="CityList" class="form-control"></select>
</div>
</div>
</div>```
Here is the test result:

Related

Display Required Error message IEnumerable Model

On the same view I am returning a list. Also, I have [HttpPost] to create new entry.
When the model is not valid, The ValidationSummary shows that expenseName is Required.
I would like to show Model required error Messages near each field in my View. asp-Validation-for was working when I didn't have IEnumerable model. What I have to do so I can see the validation error messages using IEnumerable model? (etc. for expenseName)
Model
[Key]
public int expenseId { get; set; }
[Column(TypeName = "nvarchar(50)")]
[Required(ErrorMessage = "The field 'Expense Name' is required")]
public string expenseName { get; set;}
public double price { get; set; }
public bool isStandard { get; set; }
public DateTime? date { get; set; }
View
#model IEnumerable<ExpenseTracker.Models.Expenses>
#Html.ValidationSummary(false, "", new { #class = "text-danger" })
#{
ViewData["Title"] = "Index";
}
<form method="post" enctype="multipart/form-data" asp-controller="Expenses" asp-action="Index">
<div>
<label for="files" class="lbl-select-file">Select Expense File</label>
<input id="files" name="postedFiles" class="btn-uploader" type="file">
</div>
<label class="expense-name-lbl" for="expenseName">Expense Name</label>
<input type="text" name="expenseName" class="expense-name-input" id="expenseName" />
**<span asp-validation-for=" " class="text-danger"></span>**
<div class="form-group form-check">
<label class="form-check-label checkbox-isStandard-form">
<input class="form-check-input" type="checkbox" name="chkeco" title="Check this if the bill is monthly/yearly" /> Is Standard?
</label>
</div>
<input type="submit" class="btn btn-success btnColor-expenses" value="Upload" />
<label id="fileName"></label>
<span class="uploaded-file">#Html.Raw(ViewBag.Message)</span>
</form>
<table class="table table-text">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.expenseName)
</th>
<th>
#Html.DisplayNameFor(model => model.price)
</th>
<th>
#Html.DisplayNameFor(model => model.isStandard)
</th>
<th>
#Html.DisplayNameFor(model => model.date)
</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.expenseName)
</td>
<td>
#Html.DisplayFor(modelItem => item.price)
</td>
<td>
<input type="checkbox" class="checkbox-isStandard" checked="#item.isStandard" />
</td>
<td>
#if (item.date.HasValue)
{
DateTime? datetimeToDate = #item.date;
string FormattedDate = datetimeToDate.Value.ToString("dd-MM-yyyy");
<label>#FormattedDate</label>
}
</td>
<td>
<a asp-action="Edit" asp-route-id="#item.expenseId">Edit</a> |
<a asp-action="Details" asp-route-id="#item.expenseId">Details</a> |
<a asp-action="Delete" asp-route-id="#item.expenseId">Delete</a>
</td>
</tr>
}
</tbody>
</table>
Controller
[HttpPost]
[ValidateAntiForgeryToken]
[PreventDuplicateRequest]
public async Task<IActionResult> Index(IFormCollection formCollection, string expenseName,
List<IFormFile> postedFiles, [Bind("expenseName,price,isStandard,date")] Expenses expenses)
{
if (ModelState.IsValid)
{
......
return View(await _context.Expenses.ToListAsync());
}
else
{
return View(await _context.Expenses.ToListAsync());
}
You can create a ViewModel which contains a List<Expenses>(you wanna display in the view) and a Expenses(you wanna upload to the controller).
ViewModel
public class ExpensesViewModel
{
//Pass the value to this parameter in the get method to display on the page
public List<Expenses> ListModel { get; set; }
public Expenses model { get; set; }
}
Then change your view code like:
#model ExpensesViewModel
#Html.ValidationSummary(false, "", new { #class = "text-danger" })
#{
ViewData["Title"] = "Index";
}
<form method="post" enctype="multipart/form-data" asp-controller="Home" asp-action="Show">
<div>
<label for="files" class="lbl-select-file">Select Expense File</label>
<input id="files" name="postedFiles" class="btn-uploader" type="file">
</div>
<div class="form-group">
<label class="expense-name-lbl" for="expenseName">Expense Name</label>
<input type="text" \ class="expense-name-input" asp-for=#Model.model.expenseName />
<span asp-validation-for="#Model.model.expenseName" class="text-danger"></span>
</div>
<div class="form-group form-check">
<label class="form-check-label checkbox-isStandard-form">
<input class="form-check-input" type="checkbox" name="chkeco" title="Check this if the bill is monthly/yearly" /> Is Standard?
</label>
</div>
<input type="submit" class="btn btn-success btnColor-expenses" value="Upload" />
<label id="fileName"></label>
<span class="uploaded-file">#Html.Raw(ViewBag.Message)</span>
</form>
<table class="table table-text">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.model.expenseName)
</th>
<th>
#Html.DisplayNameFor(model => model.model.price)
</th>
<th>
#Html.DisplayNameFor(model => model.model.isStandard)
</th>
<th>
#Html.DisplayNameFor(model => model.model.date)
</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model.ListModel)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.expenseName)
</td>
<td>
#Html.DisplayFor(modelItem => item.price)
</td>
<td>
<input type="checkbox" class="checkbox-isStandard" checked="#item.isStandard" />
</td>
<td>
#if (item.date.HasValue)
{
DateTime? datetimeToDate = #item.date;
string FormattedDate = datetimeToDate.Value.ToString("dd-MM-yyyy");
<label>#FormattedDate</label>
}
</td>
<td>
<a asp-action="Edit" asp-route-id="#item.expenseId">Edit</a> |
<a asp-action="Details" asp-route-id="#item.expenseId">Details</a> |
<a asp-action="Delete" asp-route-id="#item.expenseId">Delete</a>
</td>
</tr>
}
</tbody>
</table>
Finally, You can validate your expenseName property.
You can try to add this validation js.
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.1/jquery.validate.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validation-unobtrusive/3.2.11/jquery.validate.unobtrusive.min.js"></script>

Spring Boot doesnt return template in Post Mapping

I hope some of you have an idea about this. I'm still new to Spring but till this point I could figured out every problem myself. I'm using also Thymeleaf for the templates.
In the Controller the function for #GetMapping works as intended, but the #PostMapping function doesnt return the template which I specified in the return parameter and so the browser shows the wrong page.
The #PostMapping function gets triggered by the ajax statement in the html script.
I get no errors or warnings on server side as well as on client side. So I have no idea were the spot the mistake.
Hope some of you can spot the mistake. Thanks in advance anyway.
Controller:
#Controller
public class SpringController {
#RequestMapping(value="/tank", method = RequestMethod.GET)
public String loadData(Model model){
Tankstelle[] data = TankerAPI.getTankData(lat, lng, 5, sort, type);
model.addAllAttributes(convertdata("name", data));
model.addAllAttributes(convertdata("dist", data));
model.addAllAttributes(convertdata("price", data));
return "home";
}
#RequestMapping(value = "/tank", method = RequestMethod.POST)
public String getChangedData(#RequestBody JSONObject incomingjson) {
lat = Float.parseFloat(incomingjson.get("lat").toString());
lng = Float.parseFloat(incomingjson.get("lng").toString());
BigDecimal biglat = new BigDecimal(lat).setScale(3, RoundingMode.HALF_UP);
BigDecimal biglng = new BigDecimal(lng).setScale(3, RoundingMode.HALF_UP);
lat = biglat.floatValue();
lng = biglng.floatValue();
sort = "price"; //for seeing a difference
System.out.println(incomingjson.get("lat")+" "+incomingjson.get("lng"));
return "test"; //here it should return the template "test" but it return "home"
}
home.html:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org/">
<head>
<meta charset="UTF-8"/>
<title>guenstigertanken.de</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<style>...
</style>
</head>
<body onload="getLocation()">
<div class="ueberschriftbox"></div>
<h2 class="header">guenstigertanken.de</h2>
<h2 class="subheader">Wir finden die günstigsten Spritpreise für Sie</h2>
<div class="backrounding">
<div class="steuerelementebox"></div>
<div class="steuerelementespritsorteueberschrift">
<h2>Spritsorte</h2>
<label class="container1">Super E5
<input type="radio" id="E5" name="radio1" onclick="autoSubmit()">
<span class="checkmark1"></span>
</label>
<label class="container1">Super E10
<input type="radio" id="E10" name="radio1" onclick="autoSubmit()">
<span class="checkmark1"></span>
</label>
<label class="container1">Diesel
<input type="radio" id="Diesel" name="radio1" onclick="autoSubmit()">
<span class="checkmark1"></span>
</label>
</div>
<div class="steuerelementesortierennachueberschrift">
<h2>Sortieren nach</h2>
<label class="container2">Preis aufsteigend
<input type="radio" checked="checked" name="radio2" onclick="autoSubmit()">
<span class="checkmark2"></span>
</label>
<label class="container2">Preis absteigend
<input type="radio" name="radio2" onclick="autoSubmit()">
<span class="checkmark2"></span>
</label>
<label class="container2">Distanz aufsteigend
<input type="radio" name="radio2" onclick="autoSubmit()">
<span class="checkmark2"></span>
</label> <label class="container2">Distanz absteigend
<input type="radio" name="radio2" onclick="autoSubmit()">
<span class="checkmark2"></span>
</label>
<label class="container2" id="alph">Name alphabetisch
<input type="radio" name="radio2" onclick="autoSubmit()">
<span class="checkmark2"></span>
</label>
</div>
<div class="buttonsbox"></div>
<div class="tabellenbox"></div>
<div class="ueberuns">
<p>Über uns</p>
</div>
<div class="agb">
<p>AGB</p>
</div>
<div class="datenschutz">
<p>Datenschutz</p>
</div>
<div class="impressum">
<p>Impressum</p>
</div>
<div class="left show">
<table id="datatable">
<thead>
<tr> <th>Name</th> <th>Entfernung</th> <th>Preis</th> <th>Favorit</th> </tr>
</thead>
<tbody>
<tr> <td th:text="${name1}">AGIP</td> <td th:text="${dist1}">7km</td> <td th:text="${price1}">1,20€</td> <td><input type="checkbox"></td> </tr>
<tr> <td th:text="${name2}">Aral</td> <td th:text="${dist2}">12km</td> <td th:text="${price2}">1,23€</td> <td><input type="checkbox"></td> </tr>
<tr> <td th:text="${name3}">Esso</td> <td th:text="${dist3}">2km</td> <td th:text="${price3}">1,25€</td> <td><input type="checkbox"></td> </tr>
<tr> <td th:text="${name4}">Esso</td> <td th:text="${dist4}">10km</td> <td th:text="${price4}">1,25€</td> <td><input type="checkbox"></td> </tr>
<tr> <td th:text="${name5}">Esso</td> <td th:text="${dist5}">5km</td> <td th:text="${price5}">1,25€</td> <td><input type="checkbox"></td> </tr>
<tr> <td th:text="${name6}">BP</td> <td th:text="${dist6}">13km</td> <td th:text="${price6}">1,35€</td> <td><input type="checkbox"></td> </tr>
<tr> <td th:text="${name7}">BP</td> <td th:text="${dist7}">13km</td> <td th:text="${price7}">1,35€</td> <td><input type="checkbox"></td> </tr>
<tr> <td th:text="${name8}">BP</td> <td th:text="${dist8}">13km</td> <td th:text="${price8}">1,35€</td> <td><input type="checkbox"></td> </tr>
</tbody>
</table>
</div>
</div>
<a class="cssbuttonfavoriten" href="test.html">Favoriten></a>
<a class="cssbuttonleaderboard" href="test.html">Leaderboard></a>
<a class="cssbuttonstatistiken" href="test.html">Statistiken></a>
<script>
function getLocation() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(showPosition);
} else {
}
}
function showPosition(position) {
var posdata = '{"lat":"'+position.coords.latitude+'","lng":"'+position.coords.longitude+'","typeselect":"'+type+'"}';
$.ajax({
type: 'post',
url: '/tank',
data: JSON.stringify(posdata),
contentType: "application/json; charset=utf-8",
traditional: true,
success: function(posdata) {
//alert("ajax success: refresh page to sort after price[prob current setting]")
},
error: function(){
alert("ajax error")
}
});
}
</script>
</body>
</html>
When you make any request through ajax you just receive corresponding response in your callback function:
success: function(posdata) {
//alert("ajax success: refresh page to sort after price[prob current setting]")
},
So browser will not show you a new template page. Your page is in "postdata" response

How to get sum score when checked the checkboxess?

I have score field in table of infractions. And I have many checkboxes. When I checked thed chechboxes, The total of scores are collected with ajax.
<div id="collapse6" class="panel-collapse collapse">
<div class="panel-body">
<div class="table-responsive">
<table class="table table-bordered">
#foreach($infractions as $infraction)
<tr>
<th>{{ $infraction->title }}</th>
<td>
<input type="hidden" name="infractions[{{ $infraction->id }}]" value="0" >
<input type="checkbox" value="1" onclick="{{ $infraction->score }}" name="infractions[{{ $infraction->id }}]" data-toggle="toggle">
</td>
</tr>
#endforeach
</table>
</div>
<div class="text-right"> Totlal
<span id="total">
</span>
</div>
</div>
</div>
Ajax
function scorePlus (id)
{
// var value = parseInt(document.getElementById('num'+id).value, 10);
value = isNaN(value) ? 0 : value;
value++;
document.getElementById('total').value = value;
}

create and index views combined in 1 view

I want to be able to add players and upon addition in the same I want to display them in a table similar to what page Index view offers. so what I did is combine the index and create views in 1 page.
but when debugging I'm have a resource cannot be found error.
can some one please correct where I'm going wrong
Index View:
#model IEnumerable<sportsMania.player>
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>category</h4>
<hr />
#Html.ValidationSummary(true)
<div class="form-group">
#Html.Label("Player Name")
<div class="col-md-10">
#Html.Editor("Player Name")
</div>
</div>
<div class="form-group">
#Html.Label("Team")
<div class="col-md-10">
#Html.DropDownList("team", ViewBag.team as SelectList)
</div>
</div>
<div class="form-group">
#Html.Label("Position")
<div class="col-md-10">
#Html.Editor("position")
</div>
</div>
<div class="form-group">
#Html.Label("Email")
<div class="col-md-10">
#Html.Editor("email")
</div>
</div>
<div class="form-group">
#Html.Label("Type")
<div class="col-md-10">
#Html.Editor("type")
</div>
</div>
<div class="form-group">
#Html.Label("Height")
<div class="col-md-10">
#Html.Editor("height")
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.playerName)
</th>
<th>
#Html.DisplayNameFor(model => model.team)
</th>
<th>
#Html.DisplayNameFor(model => model.position)
</th>
<th>
#Html.DisplayNameFor(model => model.email)
</th>
<th>
#Html.DisplayNameFor(model => model.type)
</th>
<th>
#Html.DisplayNameFor(model => model.height)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.playerName)
</td>
<td>
#Html.DisplayFor(modelItem => item.team)
</td>
<td>
#Html.DisplayFor(modelItem => item.position)
</td>
<td>
#Html.DisplayFor(modelItem => item.email)
</td>
<td>
#Html.DisplayFor(modelItem => item.type)
</td>
<td>
#Html.DisplayFor(modelItem => item.height)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.Id }) |
#Html.ActionLink("Details", "Details", new { id=item.Id }) |
#Html.ActionLink("Delete", "Delete", new { id=item.Id })
</td>
</tr>
}
</table>
playerController:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace sportsMania.Controllers
{
public class playerController : Controller
{
sportsEntities db = new sportsEntities();
[HttpPost]
public ActionResult Index()
{
var data = from p in db.Teams
select p.teamName;
SelectList list = new SelectList(data);
ViewBag.team = list;
return View(db.players.ToList());
}
public ActionResult Create()
{
return View();
}
[HttpPost]
public ActionResult Create(player player)
{
if (ModelState.IsValid)
{
player newRecord = new player();
newRecord.playerName = Request.Form["Player Name"];
newRecord.position = Request.Form["position"];
newRecord.type =Request.Form[ "type"];
newRecord.team =Request.Form[ "team"];
newRecord.email = Request.Form["email"];
newRecord.height = Request.Form["height"];
db.players.Add(player);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(player);
}
}
}
why I am doing this? because I don't want every time the user have to add a Player he should be redirected to the create view, I want when user finishes adding players he will hit a button "done adding" and will be redirected home.

How to pass search criteria to controller using MVC AJAX PagedList

I'm creating Advanced Search using MVC. What I mean by Advanced Search is user can do combination search, for example, user can search by category = 'Child' and name contains 'A' or age <= 10. then the result is displayed using MVC PagedList.
I followed UnobtrusiveAjax tutorial based on example from PagedList source. I defined 2 files, Index.cshtml for View and _List.cshtml for PartialView. Index contains search criteria and a button to add more clause.
and _List contains table for displaying the result using AJAX
The problem is after I filtered by code for example contains 'A' and click search then navigate to page 2 the filter value is missing and it will display code which not contains 'A'. How to solve this problem?
ViewModel:
public class WorkflowStateListViewModel
{
public IEnumerable<string> FilterField { get; set; }
public IEnumerable<string> FilterOperator { get; set; }
public IEnumerable<string> FilterString { get; set; }
public IEnumerable<string> FilterLogical { get; set; }
public PagedList<WorkflowStateListDetailViewModel> WorkflowStateListDetailVM { get; set; }
public int? Page { get; set; }
}
Controller:
public ActionResult Filter(WorkflowStateListViewModel workflowStateListVM, int? page)
{
var workflowStatesQuery = from ws in db.WorkflowStates
where ws.RowStatus == true
select ws;
if (workflowStateListVM.FilterField != null)
{
for (int i = 0; i < workflowStateListVM.FilterField.Count(); i++)
{
workflowStatesQuery = DoFilter(workflowStatesQuery, workflowStateListVM.FilterField.ElementAt(i), workflowStateListVM.FilterOperator.ElementAt(i), workflowStateListVM.FilterString.ElementAt(i));
}
}
workflowStatesQuery = workflowStatesQuery.OrderBy(ws => ws.Code);
var workflowStateListDetailVM = from ws in workflowStatesQuery
select new WorkflowStateListDetailViewModel()
{
WorkflowStateID = ws.WorkflowStateID,
Code = ws.Code,
Name = ws.Name,
Level = ws.Level,
PIC = ws.PIC
};
int pageNumber = (page ?? 1);
return PartialView("_List", workflowStateListDetailVM.ToPagedList(pageNumber, 5));
}
Index.cshtml
#model ViewModels.WorkflowStateListViewModel
#using (Ajax.BeginForm("Filter", "WorkflowState",
new AjaxOptions
{
InsertionMode = InsertionMode.Replace,
HttpMethod = "GET",
UpdateTargetId = "workflowStateList"
},
new { #class = "form-inline" }))
{
<div id="clauses">
</div>
<p>
<div class="form-group">
#Html.DropDownList("FilterField", new SelectList(Model.FilterField), new { #class = "form-control" })
</div>
<div class="form-group">
#Html.DropDownList("FilterOperator", new SelectList(Model.FilterOperator), new { #class = "form-control" })
</div>
<div class="form-group">
#Html.TextBoxFor(model => model.FilterString, new { #class = "form-control" })
</div>
<input type="submit" value="Search" class="btn btn-default" />
</p>
<p>
<div class="form-group">
<span class="glyphicon glyphicon-plus-sign"></span> Add new clause
</div>
</p>
<div id="workflowStateList">
#{ Html.RenderPartial("_List", Model); }
</div>
}
_List.cshtml
#model JOeBilling.ViewModels.WorkflowStateListViewModel
#using PagedList.Mvc;
<div class="table-responsive">
<table class="table table-striped table-hover table-condensed">
<tr>
<th></th>
<th>
Code
</th>
<th>
Name
</th>
<th>
Level
</th>
<th>
PIC
</th>
</tr>
#foreach (var item in Model.WorkflowStateListDetailVM)
{
<tr>
<td>
<span class="glyphicon glyphicon-pencil"></span>
<span class="glyphicon glyphicon-eye-open"></span>
<span class="glyphicon glyphicon-remove"></span>
</td>
<td>
#Html.DisplayFor(modelItem => item.Code)
</td>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.Level)
</td>
<td>
#Html.DisplayFor(modelItem => item.PIC)
</td>
</tr>
}
</table>
</div>
<br />
Page #(Model.WorkflowStateListDetailVM.PageCount < Model.WorkflowStateListDetailVM.PageNumber ? 0 : Model.WorkflowStateListDetailVM.PageNumber) of #Model.WorkflowStateListDetailVM.PageCount
#Html.PagedListPager(Model.WorkflowStateListDetailVM,
page => Url.Action("Filter", new { page }),
PagedListRenderOptions.EnableUnobtrusiveAjaxReplacing(new AjaxOptions() { HttpMethod = "GET", UpdateTargetId = "workflowStateList" }))
UPDATE
UPDATE 2
UPDATE 3 Response tab
<link href="/Content/PagedList.css" rel="stylesheet" type="text/css" />
<div class="table-responsive">
<table class="table table-striped table-hover table-condensed">
<tr>
<th></th>
<th>
Code
</th>
<th>
Name
</th>
<th>
Level
</th>
<th>
PIC
</th>
<th>
Created By
</th>
<th>
Created Date
</th>
<th>
Modified By
</th>
<th>
Modified Date
</th>
</tr>
<tr>
<td>
<span class="glyphicon glyphicon-pencil"></span>
<span class="glyphicon glyphicon-eye-open"></span>
<span class="glyphicon glyphicon-remove"></span>
</td>
<td>
A06
</td>
<td>
Preparing Task Code
</td>
<td>
6
</td>
<td>
</td>
<td>
JKTWLA
</td>
<td>
28/04/2014 4:24:52 PM
</td>
<td>
</td>
<td>
</td>
</tr>
<tr>
<td>
<span class="glyphicon glyphicon-pencil"></span>
<span class="glyphicon glyphicon-eye-open"></span>
<span class="glyphicon glyphicon-remove"></span>
</td>
<td>
A07
</td>
<td>
Closed
</td>
<td>
7
</td>
<td>
</td>
<td>
JKTWLA
</td>
<td>
28/04/2014 4:25:06 PM
</td>
<td>
</td>
<td>
</td>
</tr>
<tr>
<td>
<span class="glyphicon glyphicon-pencil"></span>
<span class="glyphicon glyphicon-eye-open"></span>
<span class="glyphicon glyphicon-remove"></span>
</td>
<td>
C01
</td>
<td>
New Invoice
</td>
<td>
1
</td>
<td>
</td>
<td>
JKTWLA
</td>
<td>
13/06/2014 10:49:00 AM
</td>
<td>
</td>
<td>
</td>
</tr>
</table>
</div>
<br />
Page 2 of 2
<div class="pagination-container"><ul class="pagination"><li class="PagedList-skipToPrevious"><a data-ajax="true" data-ajax-method="GET" data-ajax-mode="replace" data-ajax-update="#workflowStateList" href="/WorkflowState/Filter?page=1" rel="prev">«</a></li><li><a data-ajax="true" data-ajax-method="GET" data-ajax-mode="replace" data-ajax-update="#workflowStateList" href="/WorkflowState/Filter?page=1">1</a></li><li class="active"><a>2</a></li></ul></div>

Resources