Populating table in a partial view - asp.net-mvc

I have two model classes,
public class Claims //Goes into main view
{
public int Id { get; set; }
public string ClaimName { get; set; }
public List<ClaimDetails> ClaimList { get; set; }
}
public class ClaimDetails //Class I want in my partial view
{
public int ClaimNumber { get; set; }
public string Client { get; set; }
public int Amount { get; set; }
public string Type { get; set; }
}
My controller,
public class ClaimsController : Controller
{
public ActionResult Index()
{
Claims claims = new Claims();
claims.Id = 1;
claims.ClaimName = "Ashton";
return View(claims);
}
[HttpPost]
public ActionResult SearchList(string enterdNumber)//On click of button I come here using ajax call
{
ClaimDetails cD = new ClaimDetails();
Claims cms = new Claims();
cms.ClaimList = new List<ClaimDetails>();
cD.ClaimNumber = 10;
cD.Client = "Ashton";
cD.Amount = 2900;
cD.Type = "Vendor";
cms.ClaimList.Add(cD);
ClaimDetails cDD = new ClaimDetails();
cDD.ClaimNumber = 10;
cDD.Client = "Ashton";
cDD.Amount = 2900;
cDD.Type = "Vendor";
cms.ClaimList.Add(cDD);
return PartialView("SearchList",cms);
}
My main view in which I want my partial view to be rendered,
#using BusinessLayer
#model BusinessLayer.Claims
#{
ViewBag.Title = "Index";
}
<script src="~/Scripts/jquery-1.10.2.min.js" type="text/javascript"></script>
<script src="~/Scripts/bootstrap.min.js" type="text/javascript"></script>
<div class="row">
<div class="col-md-6">
#Html.LabelFor(m => m.Id):#Model.Id
</div>
<div class="col-md-6">
#Html.LabelFor(m => m.ClaimName):#Model.ClaimName
</div>
</div>
<div class="row">
<div class="col-md-6">
<input id="searchNumber" placeholder="Enter the number" type="text" />
</div>
<div class="row">
<button id="searchBtn" type="button">Search</button>
</div>
</div>
<div class="row">
<div class="col-md-12">
#Html.Partial("SearchList",Model.ClaimList)
</div>
</div>
<script type="text/javascript">
$(document).ready(function () {
$("#searchBtn").on("click", function () {
var enteredNum = $("#searchNumber").val();
$.ajax({
type: "POST",
url: "/Claims/SearchList",
data: { enterdNumber: enteredNum }
});
});
});
</script>
My partial view,
#model BusinessLayer.Claims
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>Claim Number</th>
<th>Client</th>
<th>Amount</th>
<th>Type</th>
</tr>
<tbody>
#if (Model.ClaimList != null)
{
foreach(var item in Model.ClaimList)
{
<tr>
<td>#item.ClaimNumber</td>
<td>#item.Client</td>
<td>#item.Amount</td>
<td>#item.Type</td>
</tr>
}
}
</tbody>
</table>
My control comes to my partial view page, which I confirmed using breakpoint, it also iterates through the foreach loop but still does not put rows into my table..Help to know where I am going wrong is appreciated, or may be my approach to partial view is itself wrong?

You're returning a partial view but you're not doing anything with it. You need to include the success callback in the ajax function and add the partial view to the DOM
$.ajax({
type: "POST",
url: '#Url.Action("SearchList", "Claims")', // use this
data: { enterdNumber: enteredNum },
dataType: 'html', // add this
success: function(response) {
$('#someElement').html(response); // add this (adjust id to suit)
}
});
and assuming you want to update the existing partial, add an id attribute to the existing container
<div class="row">
<div class="col-md-12" id="someElement"> // add id attribute
#Html.Partial("SearchList",Model.ClaimList)
</div>
</div>
Side notes:
You may want to consider including the <table> and <thead>
element in the main view and have the partial only return the
<tbody> elements to minimize the data transfered in each ajax
call.
Your method appears to be just getting data based on a filter, so
the method could be a GET rather than a POST

Related

MVC BeginCollectionItem Nested List Indexes not working

I've got a BeginCollectionItem repeater that is working perfectly, however when I try and follow the Joe Stevens blog to add nested lists it doesn't work in the way I expected.
I've used the BeginCollectionItemCore as I'm using AspNetCore, I've taken the code from here as it says it has the built in elements from the blog already in there: https://github.com/saad749/BeginCollectionItemCore
I have a main BeginCollectionItem called Section and a nested collection called SingleLine. I expected the code to output something like: Section[long-code-here].SingleLine[another-code-here].SingleLineTextBlock
however what I get is SingleLine[long-code-here].SingleLineTextBlock
I've included my code below;
Model:
namespace project.Models.SetupViewModels
{
public class SOPTopTemplateBuilderViewModel
{
public List<SectionViewModel> Section { get; set; }
}
public class SectionViewModel {
public int SectionId { get; set; }
public string SectionText { get; set; }
public string TopTempId { get; set; }
public List<SingleLineViewModel> SingleLines { get; set; }
}
}
Partial view:
#model project.Models.SetupViewModels.SectionViewModel
#using HtmlHelpers.BeginCollectionItemCore
<div class="new-section form-row">
#using (Html.BeginCollectionItem("Section"))
{
<div class="top-line">
<div class="col-12 col-md-11">
#Html.HiddenFor(m => m.SectionId, new { #class="id" })
#Html.EditorFor(m => m.SectionText, new { #class = "form-control limit-form"})
</div>
<div class="col-12 col-md-1">
</div>
</div>
}
<div class="main-row">
<div class="buttons-div">
<button id="add-single-line" type="button" data-containerPrefix="#ViewData["ContainerPrefix"]">Add Single Text</button>
</div>
</div>
<div class="main-row">
</div>
</div>
Ajax to add new line:
var form = $('form');
var recipients = $('.main-row');
$("#add-single-line").click(function(){
$.ajax({
type: "POST",
url: '#Url.Action("GetNewSingleLine")',
data: { "containerPrefix": recipients.data("containerPrefix") },
success: function (data) {
recipients.append(data);
}
});
});
EditorFor:
#model project.Models.SetupViewModels.SingleLineViewModel
#using HtmlHelpers.BeginCollectionItemCore
#using (Html.BeginCollectionItem("SingleLine"))
{
<div class="single-line-row">
#Html.HiddenFor(m => m.SingleLinkTextID, new { #class="id" })
#Html.TextBoxFor(m => m.SingleLinkTextBlock, new { #class = "form-control limit-form"})
</div>
}
EditFor Controller:
public ActionResult GetNewSingleLine(string containerPrefix)
{
ViewData["ContainerPrefix"] = containerPrefix;
return PartialView("SingleLineViewModel", new SingleLineViewModel());
}
I struggled with this exact issue for a while until I happened upon this post - which ended up leading me to an answer (thank you!).
In the example above, it is storing the prefix in the button.add-single-line but attempting to load it from the div.main-row so you probably are getting 'undefined' as the prefix. By pulling from the same item which cached the value, the code above will do what is intended.

Display a list in a partial view at post

I have this code in my controller:
[HttpPost]
public ActionResult Index(double userLat, double userLng)
{
var context = new weddingspreeEntities();
var coordinates = context.Venues
.Select(loc => new { vname = loc.VenueName, lat = loc.VenueLat, lng = loc.VenueLong })
.ToList();
string venueName = string.Empty;
List<SearchModel.DistLocation> venDistList = new List<SearchModel.DistLocation>();
for (int i = 0; i < coordinates.Count; i++)
{
string name = coordinates[i].vname;
double? lat = coordinates[i].lat;
double? lng = coordinates[i].lng;
var loc1Lat = lat.Value;
var loc1Lng = lng.Value;
var loc2Lat = userLat;
var loc2Lng = userLng;
double distance = TrackingHelper.CalculateDistance(
new SearchModel.Location() { Latitude = loc1Lat, Longitude = loc1Lng },
new SearchModel.Location() { Latitude = loc2Lat, Longitude = loc2Lng });
//convert kilometers to miles
double distMiles = distance * 0.621371192;
venueName = name;
venDistList.Add(new SearchModel.DistLocation() { venName = name, Distance = distMiles });
}
return View(venDistList);
}
I have this code in my view:
<div class="row">
<div class="form-group">
<div class="col-md-6">
#using (Html.BeginForm("Search", "Home", FormMethod.Post))
{
#*#Html.TextBoxFor(model => model.cityName)*#
<label>Enter City and State or Zip Code</label>
<input type="text" id="citystate" name="citystate" />
<label>Enter Your Wedding Date</label>
<input class="datefield" data-val="true" data-val-required="Date is required" id="weddingDate" name="weddingDate" type="date" value="1/11/1989" />
<label>Enter Your Guest Count</label>
<input type="text" id="guestcount" name="guestcount" />
<input type="button" id="search" name="search" value="Search for Venues" />
}
</div>
<!--This is the div where the google map will render -->
<div class="col-md-6">
<div id="map_canvas" style="height: 600px;"></div>
</div>
</div>
</div>
<div>
#Html.Partial("_SearchResults")
</div>
I have omitted some of my view for brevity
This is the partial view I am trying to render:
#model IEnumerable<WeddingSpree_Alpha.Models.SearchModel.DistLocation>
#{
Layout = null;
}
#using (Html.BeginForm("Index", "Home", FormMethod.Post))
{
foreach (var item in Model)
{
#item.venName
#item.Distance
}
}
What I am trying to do is to have the user enter the values in the search box and then after the click post the results (in the list named venDistList) to the view using a foreach statement.
The model looks like this:
public class SearchModel
{
public string cityName { get; set; }
public DateTime weddingDate { get; set; }
public int guestCount { get; set; }
public class Location
{
public double Latitude { get; set; }
public double Longitude { get; set; }
}
public class DistLocation
{
public string venName { get; set; }
public double Distance { get; set; }
}
}
I would like the list results to populate after the button click (post) on the page. I thought my code would do that however. I get the following error:
System.NullReferenceException: 'Object reference not set to an instance of an object'
I know that error happens when you try to use a model that is not populated yet but I thought I did that in my controller code? What exactly could be throwing that error?
This is the controller code for my partial view:
public ActionResult _SearchResults(SearchModel model)
{
return View();
}
If you are not at least instantiating an instance of IEnumerable to pass back (even if it is empty) then it will throw the null reference when you try to iterate throught the model in the partial view.
Edit: (Code trimmed down for example) Your original error is that you are trying to iterate through an object that does not exist. The below will show you how to make user of an Ajax call on your form submit to dynamically generate your partial view and attach it to your main page
Controller:
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult _SearchResults(string citystate, DateTime? weddingDate, double? guestcount)
{
List<SearchModel.DistLocation> venDistList = new List<SearchModel.DistLocation>();
venDistList.Add(new SearchModel.DistLocation() { venName = "weee1", Distance = 2 });
venDistList.Add(new SearchModel.DistLocation() { venName = "weee2", Distance = 4 });
venDistList.Add(new SearchModel.DistLocation() { venName = "weee3", Distance = 6 });
return PartialView(venDistList);
}
Index.cshtml:
#{
ViewBag.Title = "Home Page";
}
#*This is our form which will feed our user input and drive our search results output*#
<div class="row">
<div class="form-group">
<div class="col-md-6">
<form id="searchMe">
<label>Enter City and State or Zip Code</label>
<input type="text" id="citystate" name="citystate" />
<label>Enter Your Wedding Date</label>
<input class="datefield" data-val="true" data-val-required="Date is required" id="weddingDate" name="weddingDate" type="date" value="1/11/1989" />
<label>Enter Your Guest Count</label>
<input type="text" id="guestcount" name="guestcount" />
<button type="submit" class="btn btn-primary">Search for Venues</button>
</form>
</div>
</div>
</div>
<div class="row">
#*This is where we want our search results to appear when user hits submit on our form*#
<div id="SearchResult"></div>
</div>
#section scripts {
<script>
$(document).ready(function () {
//When the user hit the submit button we will post the form results to our partial view controller
$('#searchMe').submit(function () {
$.ajax({
method: "POST",
url: "/Home/_SearchResults",
data: $(this).serialize(),
success: function (result) {
//When then load our partial view into our containing div on the main page
$('#SearchResult').html(result);
}
});
return false;
});
});
</script>
}
Partial View (_SearchResult.cshtml)
#model IEnumerable<deletemeweb2.Models.SearchModel.DistLocation>
#{
Layout = null;
}
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">Search Results</h3>
</div>
<div class="panel-body">
#if (Model != null || Model.Count() < 1)
{
using (Html.BeginForm("Index", "Home", FormMethod.Post))
{
foreach (var item in Model)
{
<p>#item.venName</p>
<p>#item.Distance</p>
}
}
}
else
{
<p>No results found</p>
}
</div>
</div>

Mvc 5 pagination using view model

Hi i am newbie to Mvc i have a json service which returns a list of walletstatementlogs based on fromdate and todate. I have a controller TopUpReqLogController every time when i hit the action index of the controller it will go to service and fetch the data and returns to view as Ipagedlist and genrates pagelinks. How do i prevent servicecall everytime in TopUpReqLogController index action i just want to load service data once and pass it to index and display data in pages using int ? page please suggest
public class WalletTopUpRequest
{
public string SlNo { get; set; }
public string Sequence { get; set; }
public string Merchant { get; set; }
public string CustomerCode { get; set; }
public string CustomerName { get; set; }
public string BankName { get; set; }
public string TransactionDate { get; set; }
public string Reference { get; set; }
public string Amount { get; set; }
public string ApprovalStatus { get; set; }
public string ApproveUser { get; set; }
public string ApprovalDate { get; set; }
public string RemarKs { get; set; }
}
public ViewResult Index(int? page)
{
int pageSize = 3;
int pageNumber = (page ?? 1);
List<WalletTopUpRequest> wallettoprq = new List<WalletTopUpRequest>();
if (page == null)
{
AgentBusiness business = new AgentBusiness();
var result = business.Topuprequestlog("99910011010", "99810001110", "jBurFDoD1UpNPzWd/BlK4hVpV8GF+0eQT+AfNxEHHDKMB25AHf6CVA==", "25052017000000", "01062017000000");
wallettoprq = result.wallettopuprequest.ToList();
var viewmodel = wallettoprq.ToPagedList(pageNumber, pageSize);
return View(viewmodel);
}
return View(wallettoprq.ToPagedList(pageNumber, pageSize));
}
#using PagedList;
#using PagedList.Mvc;
#model IPagedList<HaalMeer.MVC.Client.Models.WalletTopUpRequest>
#{
Layout = "~/Views/Shared/_Layout.cshtml";
}
<html>
<head>
</head>
<body>
<div id="page-wrapper">
<div class="page-title-container">
#*<div class="container-fluid">*#
<div class="page-title pull-left">
<h2 class="entry-title">Topup Request Log</h2>
</div>
<ul class="breadcrumbs pull-right">
<li>Home</li>
<li class="active">Topup Request Log</li>
</ul>
</div>
</div>
<section id="content" class="gray-area">
<div class="container">
<div class="row">
<div class="col-md-3">
</div>
#using (Html.BeginForm("Index", "TopUpReqLog", FormMethod.Get))
{
<div class="col-md-3">
<div class="form-group">
<label>From Date</label>
<div class="datepicker-wrap blue">
#*<input type="text" name="date_from" class="input-text full-width" placeholder="mm/dd/yy" style="background-color: #fff" />*#
#Html.TextBox("Fromdate", ViewBag.fromdate as string, new { #class = "input-text full-width", #placeholder = "mm/dd/yyy",#style = "background-color: #fff" }) <br />
</div>
</div>
</div>
<div class="col-md-3">
<div class="form-group">
<label>To Date</label>
<div class="datepicker-wrap blue">
#*<input type="text" name="date_from" class="input-text full-width" placeholder="mm/dd/yy" style="background-color: #fff" />*#
#Html.TextBox("Todate", ViewBag.todate as string, new { #class = "input-text full-width", #placeholder = "mm/dd/yyy", #style = "background-color: #fff" }) <br />
</div>
</div>
<button type="submit">Submit</button>
</div>
}
<div class="col-md-3">
</div>
</div>
<div class="row">
<div class="col-md-12 col-sm-12">
<div class="table-responsive">
<table class="table">
<tr class="info" style="text-align: center; font-weight: bold; color: #000">
<td class="col-md-1">Sl</td>
<td class="col-md-2">Date</td>
<td class="col-md-1">Bank Ref.</td>
<td class="col-md-1">Bank Name</td>
<td class="col-md-2">Remarks</td>
<td class="col-md-1">Amount</td>
<td class="col-md-1">Status</td>
<td class="col-md-2">Action Date</td>
</tr>
#foreach (var item in Model)
{
<tr>
<td class="hmcenter">#Html.DisplayFor(modelItem => item.SlNo)</td>
<td class="hmcenter">#Html.DisplayFor(modelItem => item.TransactionDate)</td>
<td class="hmcenter">#Html.DisplayFor(modelItem => item.Reference)</td>
<td class="hmcenter">#Html.DisplayFor(modelItem => item.BankName)</td>
<td class="hmleft">#Html.DisplayFor(modelItem => item.RemarKs)</td>
<td class="hmright">#Html.DisplayFor(modelItem => item.Amount) </td>
<td class="hmcenter">#Html.DisplayFor(modelItem => item.ApprovalStatus)</td>
<td class="hmcenter">#Html.DisplayFor(modelItem => item.ApprovalDate)</td>
</tr>
}
</table>
<br/>
Page #(Model.PageCount<Model.PageNumber? 0 : Model.PageNumber) of #Model.PageCount
#Html.PagedListPager(Model, page => Url.Action("Index",new { page
}))
#*<div class="form-group">
<ul class="pagination">
<li>1</li>
<li class="active">2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
</div>*#
</div>
</div>
</div>
</div>
</section>
So, from what I understand you want just make it work only on client side. If your model is not empty this code should work. If you want to load data as one result and make pagination on client side, then IPageList is not what you are looking for. Because, it is used only on the server side, and always returns ONE page of data to brake large results. You also can try to pass list of data to the view and turn it to IPageList result in the view and display each
page in tab, but is not a good practice. I would use datatables in this situation to make pagination only on the client side using regular data list:
https://datatables.net/.
Hint to improve current code:
Controller:
public ViewResult Index(int? page = 1)
{
AgentBusiness business = new AgentBusiness();
var result = business.Topuprequestlog("99910011010", "99810001110", "jBurFDoD1UpNPzWd/BlK4hVpV8GF+0eQT+AfNxEHHDKMB25AHf6CVA==", "25052017000000", "01062017000000");
return View(result.wallettopuprequest.ToPagedList(pageNumber, 3));
}
View:
#Html.PagedListPager(Model, page => Url.Action("Index", new { page }), PagedListRenderOptions.ClassicPlusFirstAndLast)
Below example shows the paging to be done at server side and Client Side :
Here is my Model :
public partial class Employee
{
public int Id { get; set; }
public string FName { get; set; }
public string Lname { get; set; }
}
Action:
public ActionResult Index(int? Page)
{
return View();
}
/// returns Partial View
public ActionResult _PartialIndex(int? Page)
{
return PartialView(db.Employees.ToList().ToPagedList(Page ?? 1, 10));
}
Views :
1.Index View :Index.cshtml
#{
ViewBag.Title = "Index";
}
<script src="https://cdn.jsdelivr.net/jquery.ajax.unobtrusive/3.2.4/jquery.unobtrusive-ajax.min.js"></script>
<script>
$(document).ready(function () {
$('#loading').show();
debugger;
var Page = '';
$.ajax({
url: '/Employees/_PartialIndex',
contentType: "application/json; charset=utf-8",
type: 'get',
datatype: 'html'
}).success(function (result) {
$('#main').html(result);
$('#loading').hide();
});
});
</script>
<h2>Index</h2>
<div class="col-md-8 col-md-offset-2">
<center>
<div id="loading" style="display:none; z-index:200; position:absolute; top:50%; left:45%;">
<img src="~/Content/loading.gif" />
</div>
</center>
<div id="main">
</div>
</div>
2.Partial View :_PartialIndex.cshtml
#using PagedList.Mvc
#using PagedList;
#model IPagedList<samplePaging.Models.Employee>
#{
ViewBag.Title = "Index";
}
<h2>Employee List</h2>
<table class="table">
<tr>
<th>
First Name
</th>
<th>
Last Name
</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.FName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Lname)
</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>
<center>
#Html.PagedListPager(Model, page => Url.Action("_PartialIndex", new { page }), PagedListRenderOptions.EnableUnobtrusiveAjaxReplacing(new PagedListRenderOptions() { DisplayPageCountAndCurrentLocation = true }, new AjaxOptions() { HttpMethod = "GET", UpdateTargetId = "main", LoadingElementId = "loading" }))
</center>
If you want to do the paging at client side then follow below steps:
Action:
public ActionResult JsonIndex(int? Page)
{
return Json(db.Employees.ToList(), JsonRequestBehavior.AllowGet);
}
View:
#{
ViewBag.Title = "Index2";
}
<h2>Index2</h2>
<link rel="stylesheet" type="text/css" href="//cdn.datatables.net/1.10.10/css/jquery.dataTables.min.css">
<script type="text/javascript" language="javascript" src="//cdn.datatables.net/1.10.10/js/jquery.dataTables.min.js"></script>
<script>
$(document).ready(function () {
//Call EmpDetails jsonResult Method
$.getJSON("/Employees/JsonIndex",
function (json) {
var tr;
//Append each row to html table
for (var i = 0; i < json.length; i++) {
tr = $('<tr/>');
tr.append("<td>" + json[i].FName + "</td>");
tr.append("<td>" + json[i].LName + "</td>");
$('table').append(tr);
}
$('#EmpInfo').DataTable();
});
});
</script>
<hr />
<div class="form-horizontal">
<table id="EmpInfo" class="table table-bordered table-hover">
<thead>
<tr>
<th>Fname</th>
<th>LName</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
Hope this help you !

posting data from partial view on main view then submitting to controller

I have a MVC model as follows
public class ListSampleModel
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int SampleId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public IList<PointOfContact> lstPoc { get; set; }
}
public class PointOfContact
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int PocID { get; set; }
public string EmailAddress { get; set; }
public string PhoneNumber { get; set; }
}
What I have done is, create "PointOfContact" as a partial view on a jquery dialog and on "save" button click it shows the data on the main view in labels (I will have multiple point of contacts), now on submit I want this data along with the property values of ListSampleData to be posted back to the controller.
The issue is, the data related to simple properties are returned back but the list is always null.
below is my View
#model MVCDataFlowSample.Models.ListSampleModel
#using (Html.BeginForm("Create", "ListSample", FormMethod.Post))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>ListSampleModel</legend>
<div class="editor-label">
#Html.LabelFor(model => model.FirstName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.FirstName)
#Html.ValidationMessageFor(model => model.FirstName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.LastName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.LastName)
#Html.ValidationMessageFor(model => model.LastName)
</div>
<div id="dialog1" class="ui-dialog" style="background-color:gray;"></div>
<div id="data">
</div>
<p>
<input type="button" value="Add More..." id="btnAdd" />
</p>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
Javascript on Main View
<script type="text/javascript">
$(document).ready(function () {
$('#btnAdd').on('click', function () {
$('#dialog1').dialog({
autoOpen: true,
position: { my: "center", at: "center", of: window },
width: 1000,
resizable: false,
title: 'Add User Form',
modal: true,
open: function () {
$(this).load('#Url.Action("PocPartial", "ListSample")');
},
buttons: {
"Save User": function () {
addUserInfo();
$(this).dialog("close");
},
Cancel: function () {
$(this).dialog("close");
}
}
});
return false;
});
function addUserInfo(email, phone) {
var text = "<div id='EmailAddress'>Email Address:" + $("#EAddress").val() + "</div><div id='PhoneNumber'>Phone Number:" + $("#PhNo").val() + "</div>";
$("#data").append(text);
}
});
</script>
Partial View
#model MVCDataFlowSample.Models.PointOfContact
<div>
#Html.Label("EmailAddress:")
<div>
#Html.TextBoxFor(x => x.EmailAddress, new { id = "EAddress" })
</div>
#Html.Label("PhoneNumber:")
<div>
#Html.TextBoxFor(x => x.PhoneNumber, new { id = "PhNo" })
</div>
</div>
any help will be appreciated.
The contents of DIV elements are not submitted as form data. If you'd like that data to be submitted, add it to the DOM as hidden INPUT elements in addition to your DIVs. You'll also need to format their names correctly so that MVC knows how to bind them. See this article for how complex objects are bound in MVC.
I posted partial view data to the main page's post action You can modify the idea to any of your suits
Partial View
<select name="Country">
<option>Indian</option>
<option>Africa</option>
</select>
<select name="State">
<option>Kerala</option>
<option>TamilNadu</option>
</select>
<select name="City">
<option>Thrissur</option>
<option>Palakkad</option>
</select>
Index Page
#{
ViewBag.Title = "IndexTestPost";
}
<h2>IndexTestPost</h2>
#using(Html.BeginForm()){
#Html.Partial("~/Views/_PartialPagePostCountry.cshtml");
<input type="submit" />
}
Class To Catch Post Data
public class CountryCityState
{
public string Country { get; set; }
public string State { get; set; }
public string City { get; set; }
}
Controller
public class TestPostPartialController : Controller
{
// GET: TestPostPartial
public ActionResult IndexTestPost()
{
return View();
}
[HttpPost]
public ActionResult IndexTestPost(CountryCityState CtnCtySta)
{
return View();
}
}

How to Apply a Customized Editor Template for View Model in MVC 4

I have what I think is a easy problem but for the life of me I cant figure it out. I have a form which imports many emails from a multi-line text box. From that import, I generate a report that tells the user the status of the imported emails and any errors. I can generate the report data fine, but cant seem to display the "Errors" field properly in the view. The problem appears to be, the editor template for the "Errors" field, is not being used. My question is, how do I get the view to use and render the editor template for the "Errors" field. I have tried using UIHint, but it doesn't work. Any help would be appreciated.
ViewModels.cs
//**************************Report View Models***************************************
public class ShowErrors
{
public string EmailAddress { get; set; }
public string ErrorDescription { get; set; }
}
public class ReportViewModel
{
public int TotalEmails { get; set; }
public int SuccessEmails { get; set; }
public int DuplicateEmails { get; set; }
public int InvalidEmails { get; set; }
[UIHint("ShowErrors")]
public virtual ICollection<ShowErrors> Errors { get; set; }
}
public static class ViewModelHelpers
{
//*************************ReportViewModel Helpers**************************************
public static ShowErrors ShowErrors_ViewModel_To_Domain(this ShowErrors item)
{
var showErrors = new ShowErrors
{
EmailAddress = item.EmailAddress,
ErrorDescription = item.ErrorDescription
};
return (showErrors);
}
}
Controller for the Report:(Dont think the problem is here, I can generate the data for the report, just cant display it properly.
public ActionResult Import_Report(EmailEditViewModel emailEditViewModel)
{
string emailAddress = null;
string[] emailArray = Request.Form["ImportEmails"].Split (new string[] { System.Environment.NewLine }, StringSplitOptions.None);
var entityModified = new EmailContact();
var reportViewModel = new ReportViewModel();
Regex regex = new Regex(#"^([\w\.\-]+)#([\w\-]+)((\.(\w){2,3})+)$"); //Regular Expression that checks email address is valid
List<ShowErrors> errorList = new List<ShowErrors>();
foreach (string item in emailArray)
{
ShowErrors errorItem = new ShowErrors();
emailAddress = item.Trim();
reportViewModel.TotalEmails += 1;
Match match = regex.Match(emailAddress); //Check email is in valid format
if (emailAddress == null || emailAddress == "")
{
reportViewModel.TotalEmails -= 1;
}
else if (!match.Success)
{
//Log this email as duplicate
reportViewModel.InvalidEmails += 1;
errorItem.EmailAddress = emailAddress;
errorItem.ErrorDescription = "Invalid Email";
errorList.Add(errorItem);
}
else if (_globalClasses.IsDuplicateEmail(emailAddress) > 0)
{
//Log this email as duplicate
reportViewModel.DuplicateEmails += 1;
errorItem.EmailAddress = emailAddress;
errorItem.ErrorDescription = "Duplicate Email";
errorList.Add(errorItem);
}
else
{
entityModified.EmailAddress = emailAddress;
entityModified.ActiveCampaigns = entityModified.Campaigns.Count(); //Calculates how many campaigns a contact is a member
try
{
db.EmailContacts.Add(_crypto.EncryptAndSanitizeEmailContacts(entityModified));
db.SaveChanges();
reportViewModel.SuccessEmails += 1;
AddOrUpdateEmailContacts(entityModified, emailEditViewModel.Campaigns); //Saves campaigns selected to this contact
db.SaveChanges();
//return RedirectToAction("Contact_List");
}
catch { }
}
}
reportViewModel.Errors = errorList;
return View(reportViewModel);
}
Here is the View:
#model HoltsCA.ViewModels.ReportViewModel
#{
ViewBag.Title = "Import_Report";
Layout = "~/Views/Shared/_LayoutDashboard.cshtml";
}
<fieldset>
<legend></legend>
<div class="row col-md-6">
<div id="bootstrapTableHeader" class="row">
<div class="col-sm-12">
<h2 style="text-align:center; color:#fff; font-size:1.3em;">Import Contacts Report</h2>
</div>
</div>
<div id="bootstrapTableRow" class="row">
<div class="col-sm-7" style="text-align:right">Total Emails:</div>
<div class="col-sm-5" style="text-align:left">#Html.DisplayFor(model => model.TotalEmails)</div>
</div>
<div id="bootstrapTableRow" class="row">
<div class="col-sm-7" style="text-align:right">Success Imported Emails:</div>
<div class="col-sm-5" style="text-align:left">#Html.DisplayFor(model => model.SuccessEmails)</div>
</div>
<div id="bootstrapTableRow" class="row">
<div class="col-sm-7" style="text-align:right">Duplicate Emails:</div>
<div class="col-sm-5" style="text-align:left">#Html.DisplayFor(model => model.DuplicateEmails)</div>
</div>
<div id="bootstrapTableRow" class="row">
<div class="col-sm-7" style="text-align:right">Invalid Emails:</div>
<div class="col-sm-5" style="text-align:left">#Html.DisplayFor(model => model.InvalidEmails)</div>
</div>
<div class="row" style="height:50px"></div>
<div id="bootstrapTableHeader" class="row">
<div class="col-sm-12">
<h2 style="text-align:center; color:#fff; font-size:1.3em;">Error Report</h2>
</div>
</div>
<div id="bootstrapAccentRow" class="row">
<div class="col-sm-6" style="text-align:left">
<b>Email Address</b>
</div>
<div class="col-sm-6" style="text-align:left">
<b>Error Description</b>
</div>
</div>
<div id="bootstrapRow" class="row">
#Html.DisplayFor(model => model.Errors)
</div>
</div>
</fieldset>
<p>
#Html.ActionLink("Edit", "Edit", new { /* id=Model.PrimaryKey */ }) |
#Html.ActionLink("Back to List", "Index")
</p>
Finally Here is the Editor Template ShowErrors.cshtml
#model ShowErrors
#using HoltsCA.ViewModels
<fieldset>
<div class="col-md-6" style="text-align:left;">
#Html.DisplayFor(model => model.EmailAddress)
</div>
<div class="col-md-6" style="text-align:left;">
#Html.DisplayFor(model => model.ErrorDescription)
</div>
</fieldset>
I think you are trying to display errors by using editor template. Put your error template inside DisplayTemplates folder under Shared folder.
If you are using #Html.DisplayFor then your template should be in the DisplayTemplates folder and similar logic while displaying editing template. To specify which template to use you can also do
#Html.DisplayFor(model => model.Errors, "ShowErrors")
Another thing is your model.Errors is a List<ShowErrors> and inside your display template you have just #model ShowErrors instead you should display it like IEnumerable<ShowErrors> and iterate in the template to show all the errors.
#model IEnumerable<ShowErrors>
#using HoltsCA.ViewModels
#foreach(var error in Model)
{
<div class="col-md-6" style="text-align:left;">
#Html.DisplayFor(error => error.EmailAddress)
</div>
<div class="col-md-6" style="text-align:left;">
#Html.DisplayFor(error => error.ErrorDescription)
</div>
}
That's not an EditorTemplate, it's a DisplayTemplate.
You just need to create a folder named "DisplayTemplates" under Views/Shared, and put the ShowErrors.cshtml partial view in the folder.
Your model is a List<ShowErrors> not a ShowError object.
You could change your view to this:
#model List<ShowErrors>
#using HoltsCA.ViewModels
#foreach(var error in Model)
{
<fieldset>
<div class="col-md-6" style="text-align:left;">
#Html.DisplayFor(error => error .EmailAddress)
</div>
<div class="col-md-6" style="text-align:left;">
#Html.DisplayFor(error => error .ErrorDescription)
</div>
</fieldset>

Resources