ASP.Net MVC 5 Load list data via ajax - asp.net

I have a list in asp.net mvc 5
I have limited the number of records to be displayed in page.
now on scroll I do ajax call, the first call works fine but when I scroll down more it recall the function repeatedly 5 to 10 times and lost it again display the data, it was really strange, I could not find solution
My Controller:
public ActionResult Index()
{
int starting = 0;
if (Request.Form["starting"] != null)
{
starting = Convert.ToInt32(Request.Form["starting"]);
}
int takes = 15;
if (Request.Form["takes"] != null)
{
takes = Convert.ToInt32(Request.Form["takes"]);
}
//string strpost = "&ajax=1";
var query = db.MyEmployee.ToList().Skip(starting).Take(takes);
if (Request.IsAjaxRequest())
{
starting = starting+15;
query = db.MyEmployee.ToList().Skip(starting).Take(takes);
ViewData["starting"] = starting;
ViewBag.takes = takes;
return PartialView("_PartialIndex",query);
}
ViewBag.starting = starting;
ViewBag.takes = takes;
return View(query);
}
My Model:
public class Employee
{
public int Id { get; set; }
public string FullName { get; set; }
public string Email { get; set; }
}
My View and partial view code:
<div id="mypage">
#model IEnumerable<MVC5WAuth.Models.Employee>
#{
ViewBag.Title = "Index";
}
<h2>Index 1</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Id)
</th>
<th>
#Html.DisplayNameFor(model => model.FullName)
</th>
<th>
#Html.DisplayNameFor(model => model.Email)
</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Id)
</td>
<td>
#Html.DisplayFor(modelItem => item.FullName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Email)
</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>
<script type="text/javascript">
$(window).scroll(function () {
if ($(window).scrollTop() == $(document).height() - $(window).height()) {
// ajax call get data from server and append to the div
var ajax_image = "<img src='../Content/loading.GIF' >";
$('#mypage').html(ajax_image);
var params = '&starting=' + #ViewBag.starting + '&takes=' + #ViewBag.takes;
$.ajax({
url:'#Url.Action("Index", "Employees")',
type: "POST",
data: params,
})
.done(function (r) {
$('#mypage').html(r);
});
}
});
</script>

You current code is just replacing the existing view each time you scroll and make a ajax call, not updating the existing view with the next set of rows you want. You code also has some inefficiencies such as materializing all your records to an in-memory set before calling .Skip() and .Take().
You need to break this into 2 separate methods and views, one to generate the initial view, and one to return a partial of just the records you want to append to the main view.
Controller
public ActionResult Index()
{
return View();
}
public ActionResult Fetch(int startIndex)
{
query = db.MyEmployee.OrderBy(x => x.ID).Skip(startIndex).Take(15);
return PartialView(query);
}
Index.cshtml
#model IEnumerable<MVC5WAuth.Models.Employee>
....
<table class="table">
<thead>
<tr>
<th>#Html.DisplayNameFor(model => model.Id)</th>
....
</tr>
</thead>
<tbody id="tbody">
#{ Html.RenderAction("Fetch", new { startIndex = 0 }); } // generate the 1st 15 rows
</tbody>
</table>
<script type="text/javascript">
var start = 15;
var url = '#Url.Action("Fetch")';
var tbody = $('#tbody');
$(window).scroll(function () {
if ($(window).scrollTop() == $(document).height() - $(window).height()) {
....
$.get(url, { startIndex: start }, function(response) {
tbody.append(response);
start += 15; // increment for next call
});
}
});
</script>
Fetch.cshtml
#model IEnumerable<MVC5WAuth.Models.Employee>
#foreach (var item in Model)
{
<tr>
<td>#Html.DisplayFor(m => item.Id)</td>
....
</tr>
}

Related

InvalidOperationException: The model item passed into the ViewDataDictionary is of type, but this ViewDataDictionary instance

above is what i'm trying to achieve in my the view
i'm not sure what could be wrong or missing in my controller and view. when the page loads i get this error. if i return the view to a list, how do i convert model ListAccumation ToList()? if this what i need to do
InvalidOperationException: The model item passed into the ViewDataDictionary is of type 'ExposureTracker.Models.Accumulation', but this ViewDataDictionary instance requires a model item of type 'System.Collections.Generic.List`1[ExposureTracker.Models.Accumulation]
<--Controller-->
public IActionResult ViewDetails(string Identifier)
{
var ListAccumulation = new Accumulation();
var Account= _db.dbLifeData.Where(y => y.identifier == Identifier);
var userDetails = Account.FirstOrDefault(x => x.identifier == Identifier);
string strFullname = userDetails.fullName;
string strDOB = userDetails.dateofbirth;
foreach(var item in Account)
{
if(item.baserider == "BASIC")
{
ListAccumulation.insuredprod = item.benefittype;
ListAccumulation.basictotalsumassured += item.sumassured;
ListAccumulation.basictotalreinsuredamount += item.reinsurednetamountatrisk;
}
}
return View("ViewAccumulation", ListAccumulation);
}
public IActionResult ViewAccumulation()
{
return View();
}
#model IEnumerable<Accumulation>
<div class="table-responsive-md mb-1 mt-5">
<table class="table table-striped table-hover table-bordered" id="basic-datatables" cellspacing="0">
<thead class="bg-dark text-light">
<tr>
<th>Insured Prod</th>
<th>Sum Assured/Face Amount</th>
<th>Reinsured Net Amount At Risk</th>
</tr>
</thead>
<tbody>
#foreach(var item in Model)
{
<tr>
<td>#item.insuredprod</td>
<td>#item.basictotalsumassured </td>
<td>#item.basictotalreinsuredamount</td>
</tr>
}
</tbody>
</table>
</div>
</div>
1.Change your code:
var ListAccumulation = new Accumulation();
into
var ListAccumulation = new List<Accumulation>();
2.Change your foreach like below:
var accumulations = Account.Where(x => x.baserider == "BASIC").Select(x => new Accumulation
{
insuredprod = x.benefittype,
basictotalsumassured = x.sumassured,
basictotalreinsuredamount = x.reinsurednetamountatrisk
});
ListAccumulation.AddRange(accumulations);
Result:

ASP.NET unable to search encrypted table

I have an encrypted database, I am encrypting it using this StringCipher done by CraigTP on this post.
However when I try to search my database I am unable to search using Decrypted values, Since every value i encrypt is different, encrypting the search value and trying to match it to the database is useless. Now I'm decrypting the list and trying to match the search value to this decrypted list, but I still can't get results to appear. However If I search for the encrypted value grabbed directly from the DB I do get the results. I've tried everything I can think of and I'm out of ideas.
Here is my index method:
public ViewResult Index(string sortOrder, string searchString)
{
ViewBag.CurrentSort = sortOrder;
ViewBag.NameSortParm = String.IsNullOrEmpty(sortOrder) ? "Username" : "";
ViewBag.CurrentSort = sortOrder;
var Users = from s in db.Users
select s;
foreach(User element in Users)
{
element.Username = StringCipher.Decrypt(element.Username.ToString());
element.Password = StringCipher.Decrypt(element.Password.ToString());
}
if (!String.IsNullOrEmpty(searchString))
{
Users = Users.Where(s => s.Username.Contains(searchString));
}
switch (sortOrder)
{
case "Username":
Users = Users.OrderByDescending(s => s.Username);
break;
}
return View(Users.ToList());
}
And here is my Index view:
#model IEnumerable<EncryptTest.Models.User>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Create")
</p>
#using (Html.BeginForm())
{
<p>
Find by name: #Html.TextBox("SearchString")
<input type="submit" value="Search" /></p>
}
<table class="table">
<tr>
<th>
#Html.ActionLink("Username", "Index", new { sortOrder = ViewBag.NameSortParm })
</th>
<th>
Password
</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Username)
</td>
<td>
#Html.DisplayFor(modelItem => item.Password)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id = item.ID_User}) |
#Html.ActionLink("Details", "Details", new { id = item.ID_User }) |
#Html.ActionLink("Delete", "Delete", new { id = item.ID_User })
</td>
</tr>
}
</table>

How to Post correctly w/ List<Model> from the view to the controller? [duplicate]

I have a HTML table as below in my View:
<table id="tblCurrentYear">
<tr>
<td>Leave Type</td>
<td>Leave Taken</td>
<td>Leave Balance</td>
<td>Leave Total</td>
</tr>
#foreach (var item in Model.LeaveDetailsList)
{
<tr>
<td>#Html.TextBoxFor(m => item.LeaveType, new { width = "100" })</td>
<td>#Html.TextBoxFor(m => item.LeaveTaken, new { width = "100" })</td>
<td>#Html.TextBoxFor(m => item.LeaveBalance, new { width = "100" })</td>
<td>#Html.TextBoxFor(m => item.LeaveTotal, new { width = "100" })</td>
</tr>
}
</table>
I want to iterate through all the html table rows and insert the values in ADO.NET DataTable.
Simple speaking, converting HTML Table to ADO.NET DataTable.
How to extract values from HTML Table and insert into ADO.NET DataTable?
The view is based on the following model
public class LeaveBalanceViewModel
{
public LeaveBalanceViewModel()
{
this.EmployeeDetail = new EmployeeDetails();
this.LeaveBalanceDetail = new LeaveBalanceDetails();
this.LeaveDetailsList = new List<LeaveBalanceDetails>();
}
public EmployeeDetails EmployeeDetail { get; set; }
public LeaveBalanceDetails LeaveBalanceDetail { get; set; }
public List<LeaveBalanceDetails> LeaveDetailsList { get; set; }
}
In order to bind to a model on post back, the name attributes of the form controls must match the model properties. Your use of a foreach loop does not generate the correct name attributes. If you inspect the html you will see multiple instances of
<input type="text" name="item.LeaveType" .../>
but in order to bind to your model the controls would need to be
<input type="text" name="LeaveDetailsList[0].LeaveType" .../>
<input type="text" name="LeaveDetailsList[1].LeaveType" .../>
etc. The easiest way to think about this is to consider how you would access the value of a LeaveType property in C# code
var model = new LeaveBalanceViewModel();
// add some LeaveBalanceDetails instances to the LeaveDetailsList property, then access a value
var leaveType = model.LeaveDetailsList[0].LeaveType;
Since your POST method will have a parameter name (say model), just drop the prefix (model) and that's how the name attribute of the control must be. In order to do that you must use either a for loop (the collection must implement IList<T>)
for(int i = 0; i < Model.LeaveDetailsList.Count; i++)
{
#Html.TextBoxFor(m => m.LeaveDetailsList[i].LeaveType)
....
}
or use a custom EditorTemplate (the collection need only implement IEnumerable<T>)
In /Views/Shared/EditorTemplates/LeaveBalanceDetails.cshtml
#model yourAssembly.LeaveBalanceDetails
<tr>
<td>#Html.TextBoxFor(m => m.LeaveType)</td>
....
</tr>
and then in the main view (not in a loop)
<table>
.... // add headings (preferably in a thead element
<tbody>
#Html.EditorFor(m => m.LeaveDetailsList)
</tbody>
</table>
and finally, in the controller
public ActionResult Edit(LeaveBalanceViewModel model)
{
// iterate over model.LeaveDetailsList and save the items
}
With respect to your requirement, try this
jQuery(document).on("change", ".DDLChoices", function (e) {
var comma_ChoiceIds = '';
var comma_ChoicesText = '';
$('input[class="DDLChoices"]').each(function (e) {
if (this.checked) {
comma_ChoiceIds = comma_ChoiceIds + $(this).val() + ',';
comma_ChoicesText = comma_ChoicesText + $(this).parent('label').parent() + ',';
}
});
$('#ChoiceIds').val(comma_ChoiceIds);
$('#ChoiceText').val(comma_ChoicesText);
});
#using (Html.BeginForm("Actionname", "Controllername", FormMethod.Post, new { id = "frmChoices" }))
{
#Html.HiddenFor(m => m.ChoiceText, new { #id = "ChoiceText" })
#Html.HiddenFor(m => m.ChoiceIds, new { #id = "ChoiceIds" })
<div class="form-group">
<div>
<table>
<tr>
<th>Name</th>
<th>Selected</th>
</tr>
#foreach (var item in #Model.Choices)
{
<tr>
<td> <label>#item.ChoicesText</label> </td>
<td> <input class="DDLChoices" value="#item.ChoiceIds" type="checkbox" /></td>
</tr>
}
</table>
</div>
<input type="button" value="Submit" onclick="return ChoicesPoster.passChoices()"
</div>
}

Pagedlist not redirecting to next pages when clicked?

It correctly shows the number of pages, as well as the supposedly number of records per page which is 10. However, when I click page x it does not redirect to the next page of records.
I have used this code on a previous project and it works just fine. Is there anything I may have missed?
My controller:
public ActionResult Index(int? page)
{
try
{
int intPage = 1;
int intPageSize = 10;
int intTotalPageCount = 0;
List<Announcement> col_Announcement = new List<Announcement>();
int intSkip = (intPage - 1) * intPageSize;
intTotalPageCount = db.Announcements.Count();
var result = db.Announcements
.Take(intPageSize)
.ToList();
foreach (var item in result)
{
Announcement objAnnouncement = new Announcement();
objAnnouncement.AnnouncementDate = item.AnnouncementDate;
objAnnouncement.AnnouncementTitle = item.AnnouncementTitle;
objAnnouncement.AnnouncementBody = item.AnnouncementBody;
col_Announcement.Add(objAnnouncement);
}
// Set the number of pages
var _AnnouncementAsIPagedList =
new StaticPagedList<Announcement>
(
col_Announcement, intPage, intPageSize, intTotalPageCount
);
return View(_AnnouncementAsIPagedList);
}
catch (Exception ex)
{
ModelState.AddModelError(string.Empty, "Error: " + ex);
List<Announcement> col_Announcement = new List<Announcement>();
return View(col_Announcement.ToPagedList(1, 25));
}
}
My View:
#model PagedList.IPagedList<Test.Models.Announcement>
#using PagedList.Mvc;
<div class="jumbotron">
<h2>Announcements</h2>
<table class="table">
<tr>
<th>
Date Posted
</th>
<th>
Title
</th>
<th>
Body
</th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.AnnouncementDate)
</td>
<td>
#Html.DisplayFor(modelItem => item.AnnouncementTitle)
</td>
<td>
#Html.DisplayFor(modelItem => item.AnnouncementBody)
</td>
</tr>
}
</table>
Page #(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber) of #Model.PageCount
#Html.PagedListPager(Model, page => Url.Action("Index", new {page}))
</div>
You need to skip some records before you take the records
int intSkip = (page - 1) * intPageSize;
var result = db.Announcements
.Skip(intSkip)
.Take(intPageSize)
.ToList();

Not able to update the comment module on the mvc view using ajax call without refreshing the page

This is a check & mate situation for me...
I am using mvc 3.
I am trying to make a post and comment module on a single view. below is the code for the view and controller. I am able to get the post and all the comments on load but once I add a new comment through an AJAX call its is saved to the correct table in DB but I am not understanding how to update it on view without refreshing the page...
//model
public class PostViewModel
{
public bool? IsActive
{ get; set; }
public string PostDescription
{ get; set; }
...
public List<PostCommentModel> objPostCommentInfo { get; set; }
}
//Post Controller
DBEntities1 db = new DBEntities1();
public ActionResult Index(int ID)
{
int id = Convert.ToInt32(ID);
PostViewModel objPostViewModel = new PostViewModel();
List<PostViewModel> lstobjPostViewModel = new List<PostViewModel>();
PostCommentModel objPostCommentModel;
List<PostCommentModel> lstobjPostCommentModel = new List<PostCommentModel>();
var objPost = (from x in db.PostInfoes
where x.PostId == id
select x).ToList();
var objPostComment = (from y in db.PostCommentInfoes
where y.PostId == id
orderby y.CommentId descending
select y).ToList();
foreach (var x in objPost)
{
objPostViewModel.PostID = x.PostId;
objPostViewModel.IsActive = x.IsActive;
objPostViewModel.PostTitle = x.PostTitle;
objPostViewModel.PostDescription = x.PostDescription;
lstobjPostViewModel.Add(objPostViewModel);
}
foreach (var y in objPostComment)
{
objPostCommentModel = new PostCommentModel();
objPostCommentModel.PostId = y.PostId;
objPostCommentModel.IsActive = y.IsActive;
objPostCommentModel.CommentBody = y.CommentBody;
lstobjPostCommentModel.Add(objPostCommentModel);
}
objPostViewModel.objPostCommentInfo = lstobjPostCommentModel;
return View(lstobjPostViewModel);
}
//view
#model IEnumerable<MVCProjectModels.PostViewModel>
<table border="1">
#foreach (var item in Model)
{
<tr>
<td>
<text>Created By:</text>
#Html.DisplayFor(modelItem => item.PostDescription)
</td>
<td rowspan="2">
#Html.DisplayFor(modelItem => item.PostDescription)
</td>
</tr>
.....
}
</table>
<table>
<tr>
<td>
<textarea cols="10" rows="5" id="txtComment"></textarea>
</td>
</tr>
<tr>
<td>
<input id="btnPostComment" type="button" value="Post Comment" />
</td>
</tr>
</table>
<table border="1">
#foreach (var item1 in Model)
{
foreach (var item2 in item1.objPostCommentInfo)
{
<tr>
<td colspan="2">
#Html.DisplayFor(modelItem => item2.CommentBody)
</td>
</tr>
}
}
</table>
//Ajax call to update the comment (The comments gets saves to the database but I am not finding anyway to update it on the UI or View)
<script type="text/javascript">
$("#btnPostComment").click(function () {
var commentBody = $("#txtComment").val();
postComment(commentBody);
});
function postComment(commentBody) {
$.ajax({
url: "/Post/postComment", // this controller method calls a store procedure to insert the new comment in the database.
type: 'POST',
data: {
Comment: commentBody,
ID: 6
},
success: function (result) {
},
error: function () {
alert("error");
}
});
}
</script>
Please let me know if I am doing any major designing mistakes in the above module. I am new to mvc so just trying to do this by reading some books and articles so not sure if this is correct way of achieving such results. thanks
You need to name your table for easier reference:
<table border="1" id="postList">
On your view you are writing a name of a user <text>Created By:</text> but I don't see that in the model. So assuming that is saved in a session or you can retrieve it in your controller you can do something like:
public ActionResult PostComment(YourModel input){
// everything went well
// you get this from a session or from the database
var username = "the creator";
return Json(new { success = true, username});
}
On success of your ajax call:
success: function (result) {
if (result.success) {
$("#postList").append('<tr><td><text>Created By:</text>' +
result.username + '</td><td rowspan="2">' +
commentBody + '</td>');
</tr>
}
}
It will be cool though if instead of concatenating the tr string that you read it from a template and insert the necessary values. Or you can use other tools like knockout to do the binding on the client side. But that is for another question I guess.
You could just .prepend() the new comment text to the comments table in the success callback of your AJAX call:
success: function (result) {
// give your comments table a class="comments" so that the following
// selector is able to match it:
$('table.comments').prepend(
$('<tr/>', {
html: $('<td/>', {
text: commentBody
})
})
);
}

Resources