I have a following view in my project where i have one dropdown and one textbox and submit button.I want to execute following scenario.
On click of submit only,I want to display the table contents.So if there is data,it will display data or else it will display "No records found".Is it possible?
My view is as follows:
model mvclearn.Models.Employee
#{
ViewBag.Title = "menu";
}
#{
Layout = null;
}
<link href="~/Content/bootstrap.css" rel="stylesheet" />
<style>
.error {
color: red;
}
</style>
<div class="container">
<div class="container"style="width:30%">
#using (Html.BeginForm("save", "Test", FormMethod.Post))
{
#Html.DropDownListFor(m => m.Service_Code, Model.ser_code, "--select--", new { #class = "form-control", #placeholder = "Enter Service code" })
#Html.ValidationMessageFor(m => m.Service_Code, "", new { #class = "error" })
#Html.TextBoxFor(m => m.Service_Name, new { #class = "form-control", #placeholder = "Service Name" })
#Html.ValidationMessageFor(m => m.Service_Name, "", new { #class = "error" })
<input type="submit" value="submit" class="btn-block" />
}
<table class="table">
#{
if (Model.data!=null && Model.data.Count() > 0)
{
<tr>
<th>
#Html.DisplayName("Service_Code")
</th>
<th>
#Html.DisplayName("Service_Name")
</th>
</tr>
foreach (mvclearn.Models.Employee item in Model.data)
{
<tr>
<td>
#item.Service_Code
</td>
<td>
#item.Service_Name
</td>
</tr>
}
}
else
{
<p>No records found</p>
}
}
</table>
</div>
In your case, you have done a nice job but the way you are dealing with the model seems to be incorrect.You cannot use Model.data!= null statement,instead,I suggest you to do something like this.Check whether the Model's attributes are null or not!
if (Model.EmployeeName!=null ){
//your code here
}
Another possible reason for your problem is the model returns null values so check whether the model's attributes has the values when it is in the view.
Hope it helped.
You Can Embed Table tag in the If condition like this ...
#if(Model.data!=null && Model.data.Count() > 0)
{
<table>
<tr>
<td></td>
</tr>
</table>
}else{
<p>There is no records</p>
}
I am using the PagedList.mvc helper to handle the paging of my application, in all examples i have found people tend to explicitly set the page size. I wish to set the page size dynamically from data in a model as well create new pages from the data as well.
Table
I have the table stipulated in the image above, i would like it that page 1 is all entries that have the MonthInt as 1 and page 2 all entries as MonthInt 2 etc.. however i want each page size to be determined by how many entries there are for each month.. it currently dynamically sets the sizes of the pages according to the first page and only limits the first page to display entries with the MonthInt 1-3, after that it goes to the next page but doesnt follow the same rule.. Any help/suggestions would be great,
Controller Code:
// GET: Customers/Details/5
public ActionResult Details(int? id, string sortOrder, string searchString, string currentFilter, int? page)
{
Customer customer = db.Customers.Find(id);
var viewModel = new CustomerViewModel();
if (id != null)
{
IEnumerable<Vehicle> vehicles = db.Vehicles.Where(c => c.CustomerId == customer.Id);
List<Vehicle> vehiclesList = vehicles.OrderBy(m => m.MonthId).ThenBy(r => r.Register).ToList();
if (searchString != null)
{
page = 1;
}
else
{
searchString = currentFilter;
}
ViewBag.CurrentFilter = searchString;
int pageSize = vehicles.Count(m => m.MonthId <= 3);
int pageNumber = (page ?? 1);
if (!String.IsNullOrEmpty(searchString))
{
vehiclesList = vehicles.Where(r => r.Register.Contains(searchString.ToUpper())
|| r.License.Contains(searchString.ToUpper())).ToList();
}
PagedList<Vehicle> pagedList = new PagedList<Vehicle>(vehiclesList, pageNumber,pageSize);
viewModel = new CustomerViewModel()
{
Vehicles = pagedList,
Customer = customer
};
}
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
if (customer == null)
{
return HttpNotFound();
}
return View(viewModel);
}
View Code:
#model Application.ViewModels.CustomerViewModel
#using PagedList;
#using PagedList.Mvc
<link href="~/Content/PagedList.css" rel="stylesheet" type="text/css" />
#{
ViewBag.Title = "Fleet Details";
}
<div>
<h2>#Model.Customer.Name</h2>
#using (Html.BeginForm("Details", "Customers", FormMethod.Get))
{
<div class="input-group">
<div class="input-group-btn">
<div class="btn-toolbar">
#Html.TextBox("searchString", ViewBag.CurrentFilter as string, null, new {#class = "form-control", placeholder = "Find by Register/License", autofocus = "autofocus"})
<input class="btn-warning btn" type="submit" value="search"/>
</div>
</div>
</div>
}
<hr />
#if (!Model.Vehicles.Any())
{
<p>No Vehicles loaded</p>
<br />
}
else
{
<table class="table table-hover table-bordered">
<tr>
<th>#Html.DisplayName("Owner")</th>
<th>#Html.DisplayName("License")</th>
<th>#Html.DisplayName("Make")</th>
<th>#Html.DisplayName("Register")</th>
<th>#Html.DisplayName("MonthInt")</th>
<th>#Html.DisplayName("Month")</th>
</tr>
#foreach (var item in Model.Vehicles)
{
<tr>
<td>#Html.DisplayFor(modelItem => item.OwnerName)</td>
<td>#Html.DisplayFor(modelItem => item.License)</td>
<td>#Html.DisplayFor(modelItem => item.Make)</td>
<td>#Html.DisplayFor(modelItem => item.Register)</td>
<td>#Html.DisplayFor(modelItem => item.MonthId)</td>
<td>#Html.DisplayFor(modelItem => item.MonthName)</td>
<td>
<div class="btn-toolbar">
#Html.ActionLink("Edit", "Edit", "Vehicles", new { id = item.VehicleId }, new { #class = "btn btn-primary" })
#Html.ActionLink("Details", "Details", "Vehicles", new { id = item.VehicleId }, new { #class = "btn btn-default" })
#Html.ActionLink("Delete", "Delete", "Vehicles", new { id = item.VehicleId }, new { #class = "btn btn-danger" })
</div>
</td>
</tr>
}
</table>
}
<div class="btn-toolbar">
#Html.ActionLink("Add Vehicle", "Create", "Vehicles", new { id = Model.Customer.Id }, new { #class = "btn-success btn" })
#Html.ActionLink("Edit Customer Name", "Edit", new { id = Model.Customer.Id }, new { #class = "btn btn-primary" })
#Html.ActionLink("Delete Customer", "Delete", new { id = Model.Customer.Id }, new { #class = "btn-danger btn" })
#Html.ActionLink("Back to List", "Index", null, new { #class = "btn-default btn" })
</div>
<br/>
Page #(Model.Vehicles.PageCount < Model.Vehicles.PageNumber ? 0 : Model.Vehicles.PageNumber) of #Model.Vehicles.PageCount
#Html.PagedListPager(Model.Vehicles, page => Url.Action("Details",
new { page, pageSize = #Model.Vehicles.PageSize }))
Showing #Model.Vehicles.FirstItemOnPage to #Model.Vehicles.LastItemOnPage
of #Model.Vehicles.TotalItemCount Vehicles
Example: Example 1
Example 2
Solution kind of just happened while trying other things. Current solution allows for each month to be on its own page. It might not be the best solution but it works.
Added custom class to group data:
public class Group<T, TK>
{
public TK Key;
public IEnumerable<T> Values;
}
Updated ViewModel:
public PagedList<Group<Vehicle, string>> VehiclesGroup { get; set; }
Updated Details Controller:
public ActionResult Details(int? id, string searchString, string currentFilter, int? page, int? item)
{
var customer = db.Customers.Find(id);
if (customer == null)
{
return HttpNotFound();
}
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var vehicles = from f in db.Vehicles
where f.CustomerId == customer.Id
select f;
var vehiclesList = vehicles.OrderBy(m => m.MonthId).ThenBy(r => r.Register).ToList();
var groupedVehicles = from v in vehiclesList
group v by v.MonthName
into g
select new Group<Vehicle, string> { Key = g.Key, Values = g };
if (searchString != null)
{
page = 1;
}
else
{
searchString = currentFilter;
}
ViewBag.CurrentFilter = searchString;
var pageSize = vehicles.Count(v => v.MonthId <= 0);
if (pageSize == 0)
{
pageSize = 1;
}
var pageNumber = (page ?? 1);
if (!string.IsNullOrEmpty(searchString))
{
vehicles = vehicles.Where(r => r.Register.Contains(searchString.ToUpper())
|| r.License.Contains(searchString.ToUpper())
|| r.Make.Contains(searchString.ToUpper())
|| r.OwnerName.Contains(searchString.ToUpper())
|| r.Vin.Contains(searchString.ToUpper())
|| r.MonthName.Contains(searchString.ToUpper()));
vehiclesList = vehicles.ToList();
groupedVehicles = from v in vehiclesList
group v by v.MonthName
into g
select new Group<Vehicle, string> { Key = g.Key, Values = g };
}
var pagedList = new PagedList<Group<Vehicle, string>>(groupedVehicles, pageNumber, pageSize);
var viewModel = new CustomerVehicleViewModel()
{
VehiclesGroup = pagedList,
Customer = customer
};
return View(viewModel);
}
Updated View:
#model Application.ViewModels.CustomerVehicleViewModel
#using PagedList.Mvc
<link href="~/Content/PagedList.css" rel="stylesheet" type="text/css" />
#{
ViewBag.Title = "Fleet Details";
if (TempData["Error"] != null)
{
ViewBag.Error = TempData["Error"];
}
}
<h2>#Model.Customer.Name</h2>
<div class="row">
<div class="col-md-12">
<div class="row">
<div class="col-md-6" style="margin-bottom: 1%">
#using (Html.BeginForm("Details", "Customers", FormMethod.Get))
{
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="input-group">
<div class="input-group">
<span class="input-group-addon"><span class="glyphicon glyphicon-search"></span></span>
#Html.TextBox("searchString", ViewBag.CurrentFilter as string, null, new { #class = "form-control", placeholder = "Search", autofocus = "autofocus", style = "margin-right:1%" })
</div>
<div class="input-group-btn">
<input class="btn-warning btn" type="submit" value="search" />
#Html.ActionLink("Reset", null, null, null, new { #class = "btn btn-info", style = "margin-left: 5%" })
</div>
</div>
}
</div>
<div class="col-md-6">
<div class="btn-toolbar">
#Html.ActionLink("Add Vehicle", "Create", "Vehicles", new { id = Model.Customer.Id }, new { #class = "btn-success btn" })
#Html.ActionLink("Edit Customer", "Edit", new { id = Model.Customer.Id }, new { #class = "btn btn-primary" })
#Html.ActionLink("Delete Customer", "Delete", new { id = Model.Customer.Id }, new { #class = "btn-danger btn" })
#Html.ActionLink("Back to List", "Index", null, new { #class = "btn-default btn" })
#Html.ActionLink("BRN/ID", "ViewFile", "Customers", new { cid = Model.Customer.Id, id = Model.Customer.FileId }, new { #class = "btn-info btn", target = "_blank" })
</div>
</div>
</div>
</div>
</div>
#Html.ValidationMessage("", $"{ViewBag.Error}", new { #class = "text-danger" })
<hr />
#if (!Model.VehiclesGroup.Any())
{
<p>No Vehicles loaded</p>
<br />
}
else
{
<table class="table table-hover table-bordered" id="table">
<thead>
<tr>
<th>#Html.DisplayName("Owner")</th>
<th>#Html.DisplayName("License")</th>
<th>#Html.DisplayName("Make")</th>
<th>#Html.DisplayName("Register")</th>
<th>#Html.DisplayName("VIN")</th>
<th>#Html.DisplayName("Month")</th>
<th class="remove">
<button id="btnPrint" class="btn btn-warning"><span class="glyphicon glyphicon-print" aria-hidden="true"></span> Print Table</button>
</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model.VehiclesGroup)
{
foreach (var i in item.Values)
{
<tr>
<td>#Html.DisplayFor(modelItem => i.OwnerName)</td>
<td>#Html.DisplayFor(modelItem => i.License)</td>
<td>#Html.DisplayFor(modelItem => i.Make)</td>
<td>#Html.DisplayFor(modelItem => i.Register)</td>
<td>#Html.DisplayFor(modelItem => i.Vin)</td>
<td>#Html.DisplayFor(modelItem => i.MonthName)</td>
<td class="remove">
<div class="btn-toolbar">
#Html.ActionLink("Edit", "Edit", "Vehicles", new { id = i.VehicleId }, new { #class = "btn btn-primary" })
#Html.ActionLink("Details", "Details", "Vehicles", new { id = i.VehicleId }, new { #class = "btn btn-default" })
#Html.ActionLink("Delete", "Delete", "Vehicles", new { id = i.VehicleId }, new { #class = "btn btn-danger" })
#Html.ActionLink("Scan", "ViewFile", "Vehicles", new { cId = i.CustomerId, id = i.VehicleId }, new { #class = "btn btn-info", target = "_blank" })
</div>
</td>
</tr>
}
<tr>
<td colspan="3">#item.Key</td>
<td colspan="3"></td>
</tr>
}
</tbody>
</table>
}
<br />
Page #(Model.VehiclesGroup.PageCount < Model.VehiclesGroup.PageNumber ? 0 : Model.VehiclesGroup.PageNumber) of #Model.VehiclesGroup.PageCount
#Html.PagedListPager(Model.VehiclesGroup, page => Url.Action("Details",
new
{
page,
currentFilter = ViewBag.CurrentFilter,
pageSize = #Model.VehiclesGroup.PageSize
}))
Total of #Model.VehiclesGroup.TotalItemCount Pages
Updated Display of month January/page 1
Page 1
Updated Display of month February/page 2
Page 2
Updated Display of Page 3
Page 3
Hope it helps someone, or if anyone has better ideas please share!
After I delete a list item ex:2nd item out of 4 from the below code by clicking delete button on the row, it shows 1,2,3 in view instead of 1,3,4. When I debug the view it shows right value, however on page rendering TextBoxFor AeroDromeID is showing wrong. Also the delete aerodrome button shows the right value. Can some one help me to fix this.
Controller
[HttpPost]
[MultipleButton(Name = "action", Argument = "DeleteAerodrome")]
public ActionResult DeleteAerodrome(FormCollection fc)
{
int AerodromeID = Int32.Parse(fc["action:DeleteAerodrome"]);
var studentSignoutModel = new StudentSignoutViewModel();
UpdateModel<StudentSignoutViewModel>(studentSignoutModel);
if (studentSignoutModel.Aerodromes.Count > 0)
studentSignoutModel.Aerodromes.RemoveAll(m => m.AerodromeID == AerodromeID);
return View("StudentSignoutStageView", studentSignoutModel);
}
View
#if (Model.Aerodromes != null && Model.Aerodromes.Any())
{
for (int i = 0; i < Model.Aerodromes.Count; i++)
{
<tr>
<td>#Html.TextBoxFor(a => Model.Aerodromes[i].AerodromeID, new { #class = "form-control"})</td>
<td>#Html.TextBoxFor(a => Model.Aerodromes[i].CloudBase, new { #class = "form-control" })</td>
<td>#Html.TextBoxFor(a => Model.Aerodromes[i].Visibility, new { #class = "form-control" })</td>
<td>#Html.TextBoxFor(a => Model.Aerodromes[i].Wind, new { #class = "form-control" })</td>
<td>#Html.TextBoxFor(a => Model.Aerodromes[i].Crosswind, new { #class = "form-control" })</td>
<td>#Html.TextBoxFor(a => Model.Aerodromes[i].InterTempo, new { #class = "form-control" })</td>
<td>
<input type="submit" id="BtnDelAerodrome" value="#Model.Aerodromes[i].AerodromeID" name="action:DeleteAerodrome" style="font-size:1em" class="btn btn-danger" onclick="return confirm('Are you sure you want to delete the record with AerodromeID = '+ #Model.Aerodromes[i].AerodromeID);" />
</td>
</tr>
}
}
I think there should be a bug with Data Binding concept while rendering from server side, when we use TextBoxFor.
When I use html tag input with the model binder,it worked.
This is easily replicable.
I have a model:
public class EmployeeDetails
{
public int staffcode { get; set; }
public string name { get; set; }
public string designation { get; set; }
public string department { get; set; }
}
On click of Search button, employee details are fetched from the database and model properties are initialized. These values are also shown on the View.
dtEmpDetails = lib.RunSP("GetEmpDetails", lstEmpDetails);
leaveBalanceViewModel.EmployeeDetail.staffcode = Convert.ToInt32(staffCode);
leaveBalanceViewModel.EmployeeDetail.name = dtEmpDetails.Rows[0][0].ToString();
leaveBalanceViewModel.EmployeeDetail.designation = dtEmpDetails.Rows[0][1].ToString();
There is another button Save. When I click Save, the Textbox values from the View get lost because again a Submit is happening.
How can I store the model property values and keep it available during postbacks?
** Edited **
View Code is as below:
<div>
#using (Html.BeginForm("Search", "AFLeaveBalance",FormMethod.Get))
{
<table style="border:none">
<tr>
<td style="border:none">Enter staff code</td>
<td style="border:none">#Html.TextBox("staffcode", "", new { width = "100" })</td>
<td style="border:none"><input type="submit" value="Get Details" /></td>
</tr>
</table>
}
<br /><hr />
<table id="tblEmpDetails">
<tr>
<td style="background-color:#d2eef7; width:200px;text-align:left">Employee Name</td>
<td>#Html.TextBoxFor(m => m.EmployeeDetail.name, new { #readonly = "ReadOnly", #class = "ReadOnly", style = "width:300px" })</td>
#Html.HiddenFor(m => m.EmployeeDetail.name)
</tr>
<tr>
<td style="background-color:#d2eef7;width:200px;text-align:left">Designation</td>
<td >
#Html.TextBoxFor(m => m.EmployeeDetail.designation, new { #readonly = "ReadOnly", #class = "ReadOnly", style="width:300px" })
</td>
</tr>
<tr>
<td style="background-color:#d2eef7;width:200px;text-align:left">Directorate</td>
<td>#Html.TextBoxFor(m => m.EmployeeDetail.directorate, new { #readonly = "ReadOnly", #class = "ReadOnly", style = "width:300px" })</td>
</tr>
</table>
<br /><hr />
#using (Html.BeginForm("Save", "AFLeaveBalance", FormMethod.Post))
{
<table id="tblCurrentYear">
<tr style="background-color:#d2eef7;color:Black;font-weight:200">
<td colspan="4">
#Html.Label("Year: " + DateTime.Now.Year.ToString())
</td>
</tr>
<tr style="background-color:#d2eef7;color:Black;">
<td>Leave Type</td>
<td>Leave Taken</td>
<td>Leave Balance</td>
<td>Leave Total</td>
</tr>
#*#for (int i = 0; i < Model.LeaveDetailsList.Count; i++)*#
#*{*#
<tr>
<td>#Html.TextBoxFor(m => m.LeaveDetailsList[0].LeaveType, new { #class = "ReadOnly", #readonly = "readonly", style = "width:80px; text-align:center" })</td>
<td>#Html.TextBoxFor(m => m.LeaveDetailsList[0].LeaveTaken, new { width = "100" })</td>
<td>#Html.TextBoxFor(m => m.LeaveDetailsList[0].LeaveBalance, new { width = "100" })</td>
<td>#Html.TextBoxFor(m => m.LeaveDetailsList[0].LeaveTotal, new { width = "100" })</td>
</tr>
<tr>
<td>#Html.TextBoxFor(m => m.LeaveDetailsList[1].LeaveType, new { #class = "ReadOnly", #readonly = "readonly", style = "width:80px; text-align:center" })</td>
<td>#Html.TextBoxFor(m => m.LeaveDetailsList[1].LeaveTaken, new { width = "100" })</td>
<td>#Html.TextBoxFor(m => m.LeaveDetailsList[1].LeaveBalance, new { width = "100" })</td>
<td>#Html.TextBoxFor(m => m.LeaveDetailsList[1].LeaveTotal, new { width = "100" })</td>
</tr>
#*}*#
</table>
<br />
<table style="border:none">
<tr>
<td style="width:600px;text-align:left;border:none">
<input id="btnSave" type="submit" value="Save" style="width:100px" />
</td>
</tr>
</table>
}
</div>
The simplest way is to store all you need in session on the server and then to populate all you need from that session after submit.
I am looking to create an editor template for Object.cshtml to change the behavior of the Html.EditorForModel() method. I can't find any example of this using Razor. I have seen this example using MVC2 and WebForm view engine but don't know enough about razor to convert it. Even a simple example would be very helpful.
I'm just going to do the Display template and leave the rest as an exercise for the reader:)
#if (Model == null) {
<text>#ViewData.ModelMetadata.NullDisplayText</text>
} else if (ViewData.TemplateInfo.TemplateDepth > 1) {
<text>#ViewData.ModelMetadata.SimpleDisplayText</text>
} else {
<table cellpadding="0" cellspacing="0" border="0">
#foreach (var prop in ViewData.ModelMetadata.Properties.Where(pm => pm.ShowForDisplay && !ViewData.TemplateInfo.Visited(pm))) {
if (prop.HideSurroundingHtml) {
<text>#Html.Display(prop.PropertyName)</text>
} else {
<tr>
<td>
<div class="display-label" style="text-align: right;">
#prop.GetDisplayName()
</div>
</td>
<td>
<div class="display-field">
#Html.Display(prop.PropertyName)
</div>
</td>
</tr>
}
}
</table>
}
This seem to work for Editor Template for bootstrap, please let me know of any improvements
Object.cshtml
#if (Model == null)
{
<text>#ViewData.ModelMetadata.NullDisplayText</text>
}
else if (ViewData.TemplateInfo.TemplateDepth > 1)
{
<text>#ViewData.ModelMetadata.SimpleDisplayText</text>
}
else
{
foreach (var prop in ViewData.ModelMetadata.Properties.Where(pm => pm.ShowForDisplay && !ViewData.TemplateInfo.Visited(pm)))
{
if (prop.HideSurroundingHtml)
{
<text>#Html.Editor(prop.PropertyName)</text>
}
else
{
<div class="form-group">
#Html.Label(prop.PropertyName, new { #class = "control-label col-md-2", #style = "text-align:right;" })
<div class="col-md-10">
#Html.Editor(prop.PropertyName, null, new { #class = "form-control " })
#Html.ValidationMessage(prop.PropertyName, "", new { #class = "text-danger" })
</div>
</div>
}
}
}