Display Required Error message IEnumerable Model - validation

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>

Related

ASP.NET Core 3.1 MVC : sending selected checkboxes to controller

I have following list view with checkboxes:
#model IEnumerable<PaketServisAracTakip.Models.Item>
#{
ViewData["Title"] = "Yükleme Yap";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2 class="text-center text-success">#ViewBag.name İsimli Araca Yükleme Yap</h2>
<form asp-controller="Vehicle"
asp-action="LoadItem" method="post">
<br />
<input type="submit" name="submit" value="Oluştur" class="btn btn-primary" />
</form>
<table class="table table-bordered table-striped table-hover">
<thead>
<tr>
<th class="text-center">
Yüklensin mi?
</th>
<th class="text-center">
#Html.DisplayNameFor(model => model.Name)
</th>
<th class="text-center">
#Html.DisplayNameFor(model => model.Price)
</th>
<th class="text-center">
#Html.DisplayNameFor(model => model.Description)
</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>
<div class="form-check">
<label class="form-check-label" for="#item.Id" asp-validation-for="#item.Id"></label>
<input class="form-check-input" name="ids" type="checkbox" value="#item.Id" id="#item.Id">
</div>
</td>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
₺#Html.DisplayFor(modelItem => item.Price)
</td>
<td>
#Html.DisplayFor(modelItem => item.Description)
</td>
</tr>
}
</tbody>
</table>
And my item model with database integrated:
[Table("Items")]
public class Item
{
[Key]
public int Id { get; set; }
[Display(Name = "İsim")]
[Required(ErrorMessage ="{0} alanı boş bırakılamaz.")]
[MaxLength(50, ErrorMessage ="İsim 50 karakteri geçemez.")]
public String Name { get; set; }
[Display(Name = "Fiyat")]
[Required(ErrorMessage = "{0} alanı boş bırakılamaz.")]
[Range(0, Double.MaxValue, ErrorMessage = "Minimum 0 girmelisin.")]
public int Price { get; set; }
[Display(Name = "Açıklama")]
public String Description { get; set; }
}
view
So when button is clicked i want to get checked items in my controller. I tried this but its empty:
[HttpPost]
public ActionResult LoadItem(IEnumerable<Item> model)
{
return RedirectToAction("Index");
}
I also tried int array and FormCollection but didn't work. I think I need some tag helpers but don't know which.
when button is clicked i want to get checked items in my controller. I
tried this but its empty
Please check the code in the View Page, since the table doesn't in the <form> element, when you click the Submit button, the submitted form doesn't contain the related data.
Besides, to submit the model data to the controller using model binding, we should use the #for statement to loop through the entities and use hidden fields to store the related data. Please refer the following sample and change your code:
Model:
[Table("Items")]
public class Item
{
[Key]
public int Id { get; set; }
[Display(Name = "İsim")]
[Required(ErrorMessage = "{0} alanı boş bırakılamaz.")]
[MaxLength(50, ErrorMessage = "İsim 50 karakteri geçemez.")]
public String Name { get; set; }
[Display(Name = "Fiyat")]
[Required(ErrorMessage = "{0} alanı boş bırakılamaz.")]
[Range(0, Double.MaxValue, ErrorMessage = "Minimum 0 girmelisin.")]
public int Price { get; set; }
[Display(Name = "Açıklama")]
public String Description { get; set; }
public Boolean IsChecked { get; set; } //add a property to store whether the item is check or not.
}
View page:
#model List<netcore3_1sample.Models.Item>
#{
ViewData["Title"] = "ItemIndex";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2 class="text-center text-success">#ViewBag.name İsimli Araca Yükleme Yap</h2>
<form asp-controller="Home"
asp-action="LoadItem" method="post">
<br />
<input type="submit" name="submit" value="Oluştur" class="btn btn-primary" />
<br />
<table class="table table-bordered table-striped table-hover">
<thead>
<tr>
<th class="text-center">
Yüklensin mi?
</th>
<th class="text-center">
Name
</th>
<th class="text-center">
Price
</th>
<th class="text-center">
Description
</th>
</tr>
</thead>
<tbody>
#for( var i = 0; i < Model.Count;i++)
{
<tr>
<td>
<div class="form-check">
<label class="form-check-label" for="#Model[i].Id" asp-validation-for="#Model[i].Id"></label>
<input class="form-check-input" name="ids" type="checkbox" value="#Model[i].Id" id="#Model[i].Id">
#*<input type="checkbox" asp-for="#Model[i].IsChecked" />*#
<input type="hidden" asp-for="#Model[i].Id" />
</div>
</td>
<td>
#Html.DisplayFor(modelItem => Model[i].Name)
<input type="hidden" asp-for="#Model[i].Name" />
</td>
<td>
₺#Html.DisplayFor(modelItem => Model[i].Price)
<input type="hidden" asp-for="#Model[i].Price" />
</td>
<td>
#Html.DisplayFor(modelItem => Model[i].Description)
<input type="hidden" asp-for="#Model[i].Description" />
</td>
</tr>
}
</tbody>
</table>
</form>
Code in the controller:
[HttpPost]
public ActionResult LoadItem(List<Item> model, int[] ids)
{
return RedirectToAction("ItemIndex");
}
According to your code, you are using a html checkbox element to store the selected Item ID, so here we need to add an array to get the selected ids.
Besides, you could add a IsChecked property in the Item model, then change the following code:
<input class="form-check-input" name="ids" type="checkbox" value="#Model[i].Id" id="#Model[i].Id">
to
<input type="checkbox" asp-for="#Model[i].IsChecked" />
By using this method, in the controller, you could filter the selected item based on the IsChecked property.
The result like this:

Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary.EnsureCompatible(object value)

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:

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>

Partial view renders as full view

MVC 3 , ajax, c#
My partial view is rendering as a new page instead of replacing the search results table.
Controller:
public class SearchController : Controller
{
//
// GET: /Search/
private myEntities db = new myEntities();
private Repository repo = new Repository();
[HttpGet]
public ActionResult Index()
{
var model = new List<PersonViewModel>();
model = repo.GetPeople();
return View(model);
}
public PartialViewResult _SearchResult(string fname, string lname)
{
var personResult = repo.GetSearchResult(fname, lname);
return PartialView("_SearchResult", personResult);
}
}
The view:
<div class="page">
<div class="middle-col-comment-mod">
<h2>Search Existing Trespassers</h2>
<div id="search">
#using (Ajax.BeginForm("_SearchResult", "Search", null, new AjaxOptions { HttpMethod = "Post", InsertionMode = System.Web.Mvc.Ajax.InsertionMode.Replace, UpdateTargetId = "indexSearchResults" }))
{
<div class="editor-field">
<label>First Name:</label>
#Html.TextBox("FirstName")
<label style = "margin-left: 15px;">Last Name:</label>
#Html.TextBox("LastName", "", new { style = "margin-right: 15px;" })
<input type="submit" name="submit" class="skbutton" value="Search" />
</div>
}
</div>
<table id="indexSearchResults" class="data-table">
<tr>
<th>
FirstName
</th>
<th>
LastName
</th>
<th>
Gender
</th>
<th>
City
</th>
<th>
DOB
</th>
<th>
IsStudent
</th>
<th>
Actions
</th>
</tr>
#if (Model.Count() == 0)
{
<tr>
<td colspan=7>
There are currently no trespassers in the trespass database.
</td>
</tr>
}
else
{
foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.FirstName)
</td>
<td>
#Html.DisplayFor(modelItem => item.LastName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Gender)
</td>
<td>
#Html.DisplayFor(modelItem => item.DOB)
</td>
<td>
#Html.DisplayFor(modelItem => item.School)
</td>
<td>
#Html.DisplayFor(modelItem => item.IsStudent)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id = item.PersonId }) |
#Html.ActionLink("Details", "Details", new { id = item.PersonId }) |
#Html.ActionLink("Delete", "Delete", new { id = item.PersonId })
</td>
</tr>
}
}
</table>
</div>
</div>
And the partial view:
#model IEnumerable<TrespassTracker.Models.PersonViewModel>
<table>
<tr>
<th>
First Name
</th>
<th>
Last Name
</th>
<th>
Gender
</th>
<th>
Date of Birth
</th>
<th>
Is a Student?
</th>
<th>
Actions
</th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.FirstName)
</td>
<td>
#Html.DisplayFor(modelItem => item.LastName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Gender)
</td>
<td>
#Html.DisplayFor(modelItem => item.DOB)
</td>
<td>
#Html.DisplayFor(modelItem => item.IsStudent)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { /* id=item.PrimaryKey */ }) |
#Html.ActionLink("Details", "Details", new { /* id=item.PrimaryKey */ }) |
#Html.ActionLink("Delete", "Delete", new { /* id=item.PrimaryKey */ })
</td>
</tr>
}
</table>
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.js")" type="text/javascript"></script>
From my research I found the usual suspect to be the missing link to the jquery script in the partial, but I had that. I checked the network tab on my wed dev tools and found it is being called. What else could the problem be?
the script won't cause any problem and the only thing I see wrong here is the table. you are trying yo fill the table with other table which returns a table, use a div instead to update the ajax form (search result):
<div id="indexSearchResults">
<table>
..........
</table>
</div>
Try this
<div class="page">
<div class="middle-col-comment-mod">
<h2>Search Existing Trespassers</h2>
<div id="search">
#using (Ajax.BeginForm("_SearchResult", "Search", null, new AjaxOptions { HttpMethod = "Post", InsertionMode = System.Web.Mvc.Ajax.InsertionMode.Replace, UpdateTargetId = "indexSearchResults" }))
{
<div class="editor-field">
<label>First Name:</label>
#Html.TextBox("FirstName")
<label style = "margin-left: 15px;">Last Name:</label>
#Html.TextBox("LastName", "", new { style = "margin-right: 15px;" })
<input type="submit" name="submit" class="skbutton" value="Search" />
</div>
}
</div>
#if (Model.Count() == 0)
{
<label>There are currently no trespassers in the trespass database. </label>
}
else
{
foreach (var item in Model)
{
#Html.Partial("__SearchResult",item)
}
</div>
</div>
How 'bout to use jQuery do reload your result content, instead Post from your form? You can named some div with an ID and uses it as reference do jQuery.load() (considering you're using that ViewModel you passed into Index action):
1.View
#model YourModel
<!-- ... -->
<div id="search">
#using (Ajax.BeginForm("MainPostAction", "ControllerName", FormMethod.Post, new { id = "yourFormID" })
{
<div class="editor-field">
<label>First Name:</label>
#Html.TextBoxFor(model => model.FirstName)
<label style = "margin-left: 15px;">Last Name:</label>
#Html.TextBoxFor(model => model.LastName, new { style = "margin-right: 15px;" })
<input type="button" name="submit" id="searchButton" class="skbutton" value="Search" />
</div>
<div id="results"></div>
}
</div>
Javascript:
$(document).ready(function() {
$('#searchButton').click(function(event) {
$('#results').load('#Url.Action('_SearchResult', 'Search')', $('#yourFormID').serialize());
});
}
Your action remains the same.
How 'bout it?

Resources