Knockout and MVC Collection Binding - asp.net-mvc

Im trying to get started with Knockout in MVC and managed to get the normal binding/mapping working, however I am stuck when it comes to collections. So far I have the following code:
public class TestViewModel
{
public TestViewModel()
{
Persons = new List<Person>();
}
public List<Person> Persons { get; set; }
}
public class Person
{
public Person()
{
}
public string Name { get; set; }
public string Surname { get; set; }
public List<string> Children { get; set; }
}
cshtml code:
<h2>People</h2>
<div data-bind="template: { name: 'person-template', foreach: persons }"></div>
<script type="text/html" id="person-template">
<ul>
<li>
<div><span data-bind="text: name"/> <span data-bind="text: surname"/> has <span data-bind='text: children().length'/></div>
<ul data-bind="foreach: children">
<li><span data-bind="text: $data"> </span></li>
</ul>
</li>
</ul>
</script>
<script type="text/javascript">
var TestModel = function(model) {
var self = this;
self.persons = ko.observableArray(ko.utils.arrayMap(model.Persons, function(person) {
var per = new Person(person);
return per;
}));
};
var Person = function(person) {
var self = this;
self.Name = ko.observable(person.Name);
self.Surname = ko.observable(person.Surname);
self.Children = ko.observableArray(person.Children);
};
$(function() {
var data = #(Html.Raw(Json.Encode(Model)));
ko.applyBindings(new TestModel(data));
});
</script>
The problem I am having is not sure if the mapping is done well or if there is a problem with the output for the template.
Thanks

Issue was with case-sensitivity. This is the correct template
<script type="text/html" id="person-template">
<ul>
<li>
<div><span data-bind="text: Name"/> <span data-bind="text: Surname"/> has <span data-bind='text: Children().length'/></div>
<ul data-bind="foreach: Children">
<li><span data-bind="text: $data"> </span></li>
</ul>
</li>
</ul>
</script>

Related

Everything displays correctly except for the list of products of a category

I am making a webpage using ASP.NET Core MVC. It's an online store. The issue I have is that everything displays correctly except for the list of products of a category.
Category and Product have a one-to-many relationship in the SQLite database I am working with. When I list the category, id, name, description.., works superb, but the products in that category don't show.
This is the code where I have the issue. #Model.Products is the correct call, but I tried everything, from transforming it ToList(), ToString(), or searching for the products using a foreach loop:
#model Packt.Shared.Category
#{
ViewData["Title"] = "Category Details - " + Model.CategoryName;
}
<h2>Category Details</h2>
<hr/>
<div class=dl-horizontal>
<dt>Category ID</dt>
<dd>#Model.CategoryID</dd>
<dt>Category NAme</dt>
<dd>#Model.CategoryName</dd>
<dt>Category description</dt>
<dd>#Model.Description</dd>
<dt>List of products of the category</dt>
<dd>#Model.Products</dd> <!-Here it doesnt show a thing, not even with ToString() nor ToList(), also tried with Async->>
</div>
The button that launchs the code is the View button in the Index.cshtml razor page. How do I call the list of Products in the Category (1-to-many relationship)?:
#model NorthwindMvc.Models.HomeIndexViewModel
#{
ViewData["Title"] = "Radical Change";
string currentItem = "";
}
<div id="categories" class="carousel slide" data-ride="carousel"
data-interval="3000" data-keyboard="true">
<ol class="carousel-indicators">
#for (int c = 0; c < Model.Categories.Count; c++)
{
if (c == 0)
{
currentItem = "active";
}
else
{
currentItem = "";
}
<li data-target="#categories" data-slide-to="#c"
class="#currentItem"></li>
}
</ol>
<div class="carousel-inner">
#for (int c = 0; c < Model.Categories.Count; c++)
{
if (c == 0)
{
currentItem = "active";
}
else
{
currentItem = "";
}
<div class="carousel-item #currentItem">
<img class="d-block w-100"
src="~/images/category#(Model.Categories[c].CategoryID).jpeg"
alt="#Model.Categories[c].CategoryName" />
<div class="carousel-caption d-none d-md-block">
<h2>#Model.Categories[c].CategoryName</h2>
<h3>#Model.Categories[c].Description</h3>
<p>
<a class="btn btn-primary"
href="/Home/CategoryDetail/#Model.Categories[c].CategoryID">View</a>
</p>
</div>
</div>
}
</div>
<a class="carousel-control-prev" href="#categories"
role="button" data-slide="prev">
<span class="carousel-control-prev-icon"
aria-hidden="true"></span>
<span class="sr-only">Previous</span>
</a>
<a class="carousel-control-next" href="#categories"
role="button" data-slide="next">
<span class="carousel-control-next-icon"
aria-hidden="true"></span>
<span class="sr-only">Next</span>
</a>
</div>
<div class="row">
<div class="col-md-12">
<h1>Radical Change - Hairdresser</h1>
<p class="lead">
We've had #Model.VisitorCount visitors this month.
</p>
<form asp-action="ProductsThatCostMoreThan" method="get">
<input name="price" placeholder="Enter product price" />
<input type="submit" value="Submit" />
</form>
<form asp-action="Customers" method="get">
<input name="country" placeholder="Select a country" />
<input type="submit" value="Submit" />
</form>
<h2>Productos</h2>
<div id="newspaper">
<ul>
#foreach (var item in #Model.Products)
{
<li>
<a asp-controller="Home"
asp-action="ProductDetail"
asp-route-id="#item.ProductID">
#item.ProductName costs
#item.UnitPrice.Value.ToString("C")
</a>
</li>
}
</ul>
</div>
</div>
</div>
First of all, you could not use #Model.Products to show all products' info on view.Then, your action code should use Include method to retrieve the navigation properties' value.
Finally,refer to my simple demo shown below.
1.Assume that you have below models:
public class Category
{
[Key]
public long CategoryID{ get; set; }
public string CategoryName{ get; set; }
public string Description{ get; set; }
public virtual ICollection<Product> Products{ get; set; }
}
public class Product
{
[Key]
public long ProductID{ get; set; }
public string ProductName{ get; set; }
public long CategoryId{ get; set; }
public virtual Category Category{ get; set; }
}
2.For the Home/CategoryDetail, you need to use Include method to retrieve data:
public async Task<IActionResult> CategoryDetail(long? id)
{
if (id == null)
{
return NotFound();
}
var category = await _context.Category
.Include(s=>s.Products)
.FirstOrDefaultAsync(m => m.CategoryID == id);
if (category == null)
{
return NotFound();
}
return View(category);
}
3.To show Products info on Category/CategoryDetail razor view, you need to use #foreach:
#foreach(var item in Model.Products)
{
<h3>#item.ProductName</h3>
}

POSTing KnockoutJS model to MVC controller, List<T> in List<T> is empty

I have little experience with KnockoutJS so please bear with me.
I have a basic example that I want to get working so I can expand it to my project.
For this example you click the button and the AddSku method is called to return QuoteLine data with List.
However, as the diagram shows, BomDetails is empty:
Models:
public class QuoteViewModel
{
public int Id { get; set; }
public string QuoteName { get; set; }
public IList<QuoteLine> QuoteLines { get; set; }
}
public class QuoteLine
{
public string Description { get; set; }
public string Sku { get; set; }
public IList<BomDetail> BomDetails = new List<BomDetail>();
}
public class BomDetail
{
public string Name { get; set; }
}
Controller methods:
[HttpGet]
public ActionResult CreateQuote()
{
QuoteViewModel quote = new QuoteViewModel();
quote.Id = 10;
quote.QuoteName = "Test Create Quote";
quote.QuoteLines = new List<QuoteLine>();
return View(quote);
}
[HttpPost]
public ActionResult CreateQuote(QuoteViewModel viewModel)
{
if (ModelState.IsValid)
{
}
return RedirectToAction("CreateQuote");
}
[HttpGet]
public JsonResult AddSku()
{
QuoteLine line = new QuoteLine();
line.BomDetails = new List<BomDetail>();
line.Sku = "TestSku";
line.Description = "TestDescription";
line.BomDetails.Add(new BomDetail
{
Name = "BOM Detail 1"
});
line.BomDetails.Add(new BomDetail
{
Name = "BOM Detail 2",
});
return Json(line, JsonRequestBehavior.AllowGet);
}
The view:
#model EngineeringAssistantMVC.ViewModels.QuoteViewModel
<script src="~/Scripts/knockout.mapping-latest.js"></script>
<div class="container-fluid">
<h2>Create Quote</h2>
#using (Html.BeginForm("CreateQuote", "Test", FormMethod.Post, new { #id = "createQuoteForm", #class = "form-horizontal", role = Model, enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
#Html.HiddenFor(m => m.Id)
#Html.HiddenFor(m => m.QuoteName)
<h3>Quote Lines</h3>
<table class="table master-detail-table" id="receiving-table">
<thead>
<tr>
<th>SKU</th>
<th>Description</th>
</tr>
</thead>
<tbody data-bind="foreach: QuoteLines">
<tr>
<td>
<input class='form-control' data-bind='value: $data.Sku, attr: { name: "QuoteLines[" + $index() + "].Sku" } ' type='text' readonly='readonly' />
</td>
<td>
<input class='form-control' data-bind='value: $data.Description, attr: { name: "QuoteLines[" + $index() + "].Description" } ' type='text' readonly='readonly' />
</td>
</tr>
<tr class="detail-row">
<td colspan="7">
<table class="table">
<thead>
<tr>
<th>Name</th>
</tr>
</thead>
<tbody data-bind="foreach: BomDetails">
<tr>
<td>
<input class='form-control' data-bind='value: $data.Name, attr: { name: "BomDetails[" + $index() + "].Name" } ' type='text' readonly='readonly' />
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<h3>Add Sku from Db</h3>
<div class="row">
<div class="col-sm-2">
<input type="button" value="Add Sku" id="btnAddSku" class="btn btn-satcom-primary btn-wider" />
</div>
</div>
<h3>Submit</h3>
<div class="row">
<div class="col-sm-1">
<input type="submit" value="Submit" class="btn btn-satcom-primary btn-wider" id="btnSubmit" />
</div>
</div>
}
</div>
<script type="text/javascript">
$(function () {
quoteViewModel = new QuoteViewModel();
ko.applyBindings(quoteViewModel);
$('#btnAddSku').off().on('click', function () {
AddFromDb();
});
});
function QuoteViewModel() {
var self = this;
self.Id = ko.observable('#Model.Id');
self.QuoteName = ko.observable('#Model.QuoteName');
self.QuoteLines = ko.observableArray([]);
self.AddQuoteLine = function (sku, description, bomDetails) {
self.QuoteLines.push(new QuoteLineViewModel(sku, description, bomDetails));
}
}
function QuoteLineViewModel(sku, description, bomDetails) {
var self = this;
self.Sku = sku;
self.Description = description;
self.BomDetails = ko.observableArray([]);
$.each(bomDetails, function (index, item) {
self.BomDetails.push(new BomDetailViewModel(item.Name));
});
}
function BomDetailViewModel(name) {
var self = this;
self.Name = name;
}
function AddFromDb() {
$.ajax({
type: "GET",
url: '#Url.Action("AddSku", "Test")',
success: function (line) {
window.quoteViewModel.AddQuoteLine(line.Sku, line.Description, line.BomDetails);
}
});
}
I have tried so many things to get it populated but can't figure out where the problem lies, but I hope it is just something silly that I'm doing or not doing.
I have also tried using ko.mapping but I can't get that working either.
I managed to get this working so hopefully it will help somebody else in the future.
I removed the #Using (Html.BeginForm)
I changed the submit button to a normal button and added data-bind to a fucntion
<input type="button" value="Submit" class="btn btn-satcom-primary btn-wider" id="btnSubmit" data-bind="click:SaveToDatabase" />
The SaveToDatabase function:
self.SaveToDatabase = function () {
var dataToSend = ko.mapping.toJSON(self);
$.ajax({
type: "POST",
url: '#Url.Action("CreateQuote", "Test")',
contentType: 'application/json',
data: dataToSend,
success: function (data) {
},
error: function (err) {
console.log(err.responseText);
}
});
}
This correctly sends all the data to the controller.

How to pass hidden Id value to controller in asp.net mvc 3

I have to pass hidden Id value to controller. So I have tried in the following way, but I am getting values.
cs.Html:
<ul id="tree" class="dd-list">
#for (int i = 0; i < Model.DomainViews.Count(); i++)
{
<li class="dd-item">
<a href="#">
#Html.CheckBoxFor(model => model.DomainViews[i].IsChecked, new { #id = #Model.DomainViews[i].DomainID })
<label for="#Model.DomainViews[i].DomainID">#Model.DomainViews[i].DomainName</label>
#Html.HiddenFor(model => Model.DomainViews[i].DomainID, new { id = "hdnDomainID" })
</a>
<ul class="dd-list">
<li class="dd-item">
<a href="#">
<input type="checkbox" id="2">
<label for="2"> Level 2 - 1</label>
</a>
<ul class="dd-list">
<li class="dd-item">
<a href="#">
<input type="checkbox" id="3">
<label for="3"> Level 3 - 1</label>
</a>
</li>
<li class="dd-item">
<a href="#">
<input type="checkbox" id="4">
<label for="4"> Level 3 - 2</label>
</a>
</li>
</ul>
</li>
</ul>
</li>
}
</ul>
How to pass #Html.HiddenFor(model => Model.DomainViews[i].DomainID, new { id = "hdnDomainID" }) value to controller:
public ActionResult RoleCreate()
{
userType type = new userType();
List<DomainView> EmpList = type.GetAllRoleModulesViews();
Role objBind = new Role();
objBind.DomainViews = EmpList;
return View(objBind);
}
In above code how i get DomainId Value ..
public List<DomainView> GetAllRoleModulesViews()
{
using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["Admin"].ConnectionString))
{
List<DomainView> EmpList = new List<DomainView>();
SqlCommand com = new SqlCommand("MEDEIL_DomainMaster_SelectAll", conn);
com.CommandType = CommandType.StoredProcedure;
SqlDataAdapter da = new SqlDataAdapter(com);
DataTable dt = new DataTable();
conn.Open();
da.Fill(dt);
conn.Close();
foreach (DataRow dr in dt.Rows)
{
EmpList.Add(new DomainView
{
DomainID = Convert.ToInt32(dr["DomainID"]),
DomainCode = Convert.ToString(dr["DomainCode"]),
DomainName = Convert.ToString(dr["DomainName"]),
CreatedBy = Convert.ToInt32(dr["CreatedBy"] == DBNull.Value ? null : dr["CreatedBy"].ToString()),
CreatedDate = Convert.ToDateTime(dr["CreatedDate"]),
ModifiedBy = Convert.ToInt32(dr["ModifiedBy"] == DBNull.Value ? null : dr["ModifiedBy"].ToString()),
ModifiedDate = Convert.ToDateTime(dr["ModifiedDate"] == DBNull.Value ? null : dr["ModifiedDate"].ToString())
});
}
return EmpList;
}
}
Modules:
public class DomainView
{
[Key]
public int DomainID { get; set; }
public string DomainCode { get; set; }
public string DomainName { get; set; }
public int TabOrder { get; set; }
public string UserName { get; set; }
public int CreatedBy { get; set; }
public DateTime CreatedDate = DateTime.UtcNow;
public int ModifiedBy { get; set; }
public DateTime ModifiedDate = DateTime.UtcNow;
public bool IsChecked { get; set; }
public IEnumerable<DomainView> DomainViews { get; set; }
}
The easiest way I'd prefer is to use a MVC feature called Editor Templates. You would need to create a Sub-Directory EditorTemplates within the correct View Folder (or Shared Folder) and there, you'd create DomainView.cshtml. That file would contain the markup very similar to the body of your for-loop, but with DomainViews[i] removed everywhere because the Template is for a single item only:
#model DomainView // <-- you'll need your Namespace here of course
<li class="dd-item">
<a href="#">
#Html.CheckBoxFor(model => model.IsChecked, new { #id = #Model.DomainID })
<label for="#Model.DomainID">#Model.DomainName</label>
#Html.HiddenFor(model => Model.DomainID, new { id = "hdnDomainID" })
</a>
......
</li>
Within your main page, where the element <ul id="tree" class="dd-list"> is placed, your code would be:
<ul id="tree" class="dd-list">
#Html.EditorFor(model => model.DomainViews)
</ul>
The MVC Editor Template engine will generate correct names for your and when posted back, the model binder will ensure that the Array is filled correctly.

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 !

How do I populate a menu by using recursive loop?

Below are the info.
No idea how to loop the SubNav item in the View. (Ref: Loop Through Multi-Level Dynamic Menus in Asp.Net MVC)
Controller
[ChildActionOnly]
public PartialViewResult LoadNav()
{
var db = new NavDb();
List<Nav> NavCol = db.Navs.ToList<Nav>();
var navObj = CreateNavVM(0, NavCol);
return PartialView("_PVTopNav", navObj);
}
public IEnumerable<NavViewModel> CreateNavVM(int pParentId, List<Nav> pNavCol)
{
return from m in pNavCol
orderby m.DisplaySeq
where m.ParentMenuId == pParentId
select new NavViewModel()
{
MenuId = m.MenuId,
Name = m.Name,
HtmlTitle = m.HtmlTitle,
Url = m.Url,
DisplaySeq = m.DisplaySeq,
SubNav = (IEnumerator<NavViewModel>)CreateNavVM(m.MenuId, pNavCol)
};
}
ViewModel
public class NavViewModel
{
public int MenuId { get; set; }
public int ParentMenuId { get; set; }
public string Name { get; set; }
public string HtmlTitle { get; set; }
public string Url { get; set; }
public int DisplaySeq { get; set; }
public IEnumerator<NavViewModel> SubNav { get; set; }
}
Model
public class Nav
{
[Key]
public int MenuId { get; set; }
public int ParentMenuId { get; set; }
public string Name { get; set; }
public string HtmlTitle { get; set; }
public string Url { get; set; }
public int DisplaySeq { get; set; }
}
View
#model IEnumerable<yetpweb.ViewModels.NavViewModel>
#foreach (var m in Model) {
<div class="ui simple dropdown item">
#m.Name
<div class="menu">
<a class="item" href="#">Link Item</a>
<a class="item" href="#">Link Item</a>
<div class="item">
<i class="dropdown icon"></i>
Sub Menu
<div class="menu">
<a class="item" href="#">Link Item</a>
<a class="item" href="#">Link Item</a>
</div>
</div>
<a class="item" href="#">Link Item</a>
</div>
</div>
}
You can just start another razor foreach statement. In your code this would result in:
#foreach (var m in Model) {
<div class="ui simple dropdown item">
#m.Name
<div class="menu">
<a class="item" href="#">Link Item</a>
<a class="item" href="#">Link Item</a>
<div class="item">
<i class="dropdown icon"></i>
#foreach(var sub in m.SubNav) {
<div class="menu">
<a class="item" href="#">Link Item</a>
<a class="item" href="#">Link Item</a>
</div>
}
</div>
<a class="item" href="#">Link Item</a>
</div>
</div>
}

Resources