Custom Pagination With Last and Previous - ajax

I am working on an ecommerce site where I have to use custom pagination with Ajax and it's almost done. Here is an image that how it looks:
Now the issue - The red highlighted 5 is the last page and I am trying to show as follows:
I am not sure how to handle this but I've tried the following: (Almost all works except the last section)
#for (int i = 1; i <= Model.TotalPages; i++)
{
if (i == Model.CurrentPage)
{
<li class="#(i == Model.CurrentPage ? "active" : "")">#i</li>
}
else
{
<li><a class="page-number" href="javascript:void();">#i</a></li>
}
}
#if (Model.CurrentPage < Model.TotalPages)
{
<li>
<a class="last-page" href="javascript:void();">#Model.TotalPages</a> #*Here I am willing to show Last, but currently it shows the last page number 5*#
</li>
}
I am wondering how to show the name Last instead of the number I mean last page number. Again using partial view to show the details and pagination as follows:
#model OnlinePharmacy.Helpers.PagedData<OnlinePharmacy.Models.Product>
#{
ViewBag.Title = "Products";
List<OnlinePharmacy.Models.Product> products = ViewBag.Product;
}
<script src="~/Scripts/jquery-1.5.1.min.js"></script>
<script type="text/javascript">
$().ready(function () {
$(".page-number").live("click", function () { //This section deals the pagination
var page = parseInt($(this).html());
var url = '/Product/Products/';
url += 'page/' + page;
$.ajax({
url: '#Url.Action("Index")',
data: { "page": page },
success: function (data) {
$("#product-list").html(data);
}
});
window.history.pushState(
null,
'Products', // new page title
url // new url
)
});
});
$().ready(function () { //This section deals the pagination for the last page
$(".last-page").live("click", function () {
var page = parseInt($(this).html());
var url = '/Product/Products/';
url += 'page/' + page;
$.ajax({
url: '#Url.Action("Index")',
data: { "page": page },
success: function (data) {
$("#product-list").html(data);
}
});
window.history.pushState(
null,
'Products',
url
)
});
});
</script>
<div id="product-list">
#Html.Partial("Index")
</div>
I am sharing the models here for the products and pagination:
public class Product
{
public int ProductId { get; set; }
public int CategoryId { get; set; }
public string ProductName { get; set; }
[AllowHtml]
public string cktext { get; set; }
public double Price { get; set; }
public double Stock { get; set; }
public int Status { get; set; }
public IEnumerable<SelectListItem> Categories { get; set; }
}
public class PagedData<T> where T : class
{
public IEnumerable<T> Data { get; set; }
public int TotalPages { get; set; }
public int CurrentPage { get; set; }
}
With the following action, I am getting the page no. using Ajax (Please see the Ajax section above):
public ActionResult Index(int page)
{
List<Product> products = aProductManager.GetAllProducts();
ViewBag.Product = products.OrderBy(p => p.ProductId).Skip(PageSize * (page - 1)).Take(PageSize).ToList();
var dataFromDb = new PagedData<Product>();
dataFromDb.Data = products.OrderBy(p => p.ProductId).Skip(PageSize * (page - 1)).Take(PageSize).ToList();
dataFromDb.TotalPages = Convert.ToInt32(Math.Ceiling((double)products.Count() / PageSize));
dataFromDb.CurrentPage = page;
return PartialView(dataFromDb);
}
Updated: I require to do the following (Requirement little bit changed) - Frankly speaking, I am not aware how to do the below but would appreciate valuable suggestion. Thanks.

If you need to change your text you should change last section like this:
#if (Model.CurrentPage < Model.TotalPages)
{
<li>
<a class="last-page" href="javascript:void();">Last</a>
</li>
}
To make your solution work fine i suggest you to move actual page number to data attribute of your <a> tag like this:
#if (Model.CurrentPage < Model.TotalPages)
{
<li>
<a data-page-number="#Model.TotalPages" class="last-page" href="javascript:void();">Last</a>
</li>
}
And then change your js line:
$(".last-page").live("click", function () {
var page = parseInt($(this).html());
//your other code
});
To this:
$(".last-page").live("click", function () {
var page = parseInt($(this).data('page-number'));
//your other code
});
Ofcource it will be better to change your whole js solution to data attributes.

Related

How do I populate a drop-down list with List<string> using knockout.JS

I'm playing around with knockoutJS and am struggling to get a drop-down populated with data from my model.
I'm guessing I need to convert the model data to a JSON first but for the life of me can't figure it out.
I have a basic class:
public class QuoteViewModel
{
public QuoteViewModel()
{
QuoteLines = new List<QuoteLine>();
}
public int QuoteHeaderId { get; set; }
public string QuoteNumber { get; set; }
public string Status { get; set; }
public DateTime DateCreated { get; set; }
[DisplayName("Customer")]
public SalesCustomer SelectedCustomer { get; set; }
public List<string> Customers { get; set; }
public List<QuoteLine> QuoteLines { get; set; }
}
I have an ActionMethod in a controller:
[HttpGet]
public ActionResult CreateQuote()
{
QuoteViewModel quote = new QuoteViewModel();
quote.QuoteNumber = "";
quote.Status = "P";
quote.Customers = _dbContext.SalesCustomers.Select(x => x.CustomerName).ToList();
quote.QuoteLines = new List<QuoteLine>();
return View(quote);
}
And the View():
Razor:
<select class="form-control" id="SelectedCustomer" data-bind="options: availableCustomers, optionsText: 'CustomerName', value: SelectedCustomer, optionsCaption: 'Choose...'"></select>
ViewModel:
function QuoteViewModel() {
var self = this;
self.Id = ko.observable('#Model.QuoteHeaderId');
self.QuoteNumber = ko.observable();
self.Status = ko.observable('#Model.Status');
self.DateCreated = ko.observable();
self.availableCustomers = JSON.parse('#Html.Raw(Model.Customers)');
#*$.ajax({
type: "GET",
url: '#Url.Action("GetCustomers", "Test")',
success: function (data) {
$.each(data, function (index, value) {
self.availableCustomers.push(new Customer(value));
});
},
error: function (err) {
console.log(err.responseText);
}
});*#
self.SelectedCustomer = ko.observable();
self.QuoteLines = ko.observableArray([]);
self.AddQuoteLine = function (sku, description, bomDetails) {
self.QuoteLines.push(new QuoteLineViewModel(sku, description, bomDetails));
}
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);
}
});
}
The commented out code uses ajax to get the customers and push it onto the array and that works, but is there not a way to do it directly from the model data?
Edit 1:
I don't need access to the whole SalesCustomer object, just the string name:
If I change my code as such:
Controller:
quote.Customers = _dbContext.SalesCustomers.Select(x => x.CustomerName.Trim()).ToList();
Model class property:
public List<string> Customers { get; set; }
Razor:
<select class="form-control" id="SelectedCustomer" data-bind="options: availableCustomers, value: SelectedCustomer, optionsCaption: 'Choose...'"></select>
Javascript:
self.availableCustomers = ko.observableArray([]);
var customers = '#Html.Raw(JsonConvert.SerializeObject(Model.Customers))';
self.availableCustomers = JSON.parse(customers);
self.SelectedCustomer = ko.observable();
Now the drop-down is populated with the string values of customer names. However the selected customer is not passed back to controller on POST?
Edit 2:
Well I'm not sure why its working now, but it is.
The code is the same as in Edit 1.
The only thing I can think of is I was that I erroneously had the SelectedCustomer property type still set to SalesCustomer which will obviously not work:
public SalesCustomer SelectedCustomer { get; set; }
when it should be:
public string SelectedCustomer { get; set; }
Thank you user3297291 for the assistance in pointing me in right direction.

Like button in MVC using 'Ajax.Beginform()' not able to display total likes on page

I am beginner in MVC and Ajax development and want a like button in my web, which should work like this: if the user clicks on it total likes will be incremented by 1 and if the user clicks it again (dislike) then it will decremented by 1. What I have done so far is this:
Here's the Model:
public class Like
{
public int Id { get; set; }
public virtual Video Video { get; set; }
public int VideoID { get; set; }
public string UserId { get; set; }
public virtual ApplicationUser ApplicationUser { get; set; }
}
Here is the Controller:
Post Method
[HttpPost]
public ActionResult Like(int Id, Like like)
{
if (ModelState.IsValid && User.Identity.IsAuthenticated == true)
{
like.Video = storeDB.Videos.Find(Id);
like.UserId = User.Identity.GetUserId();
var userlike = storeDB.Likes.Where(l => l.UserId == like.UserId && l.VideoID == Id);
if (userlike.Count() == 0)
{
storeDB.Likes.Add(like);
storeDB.SaveChanges();
}
else if (userlike.Count() == 1)
{
var likeDel = storeDB.Likes.FirstOrDefault(l => l.UserId == like.UserId && l.VideoID == Id);
storeDB.Likes.Remove(likeDel);
storeDB.SaveChanges();
}
List<Like> videoLikes = storeDB.Likes.Where(v => v.VideoID == Id).ToList();
int nooflikes = videoLikes.Count();
ViewBag.noLikes = nooflikes;
return Json(ViewBag.noLikes, JsonRequestBehavior.AllowGet);
}
else
{
ViewBag.Message = "Login to like this video";
return PartialView("Like", ViewBag.noLikes);
}
This is the Get method of Like:
public ActionResult Like(int id)
{
List<Like> videoLikes = storeDB.Likes.Where(v => v.VideoID == id).ToList();
int nooflikes = videoLikes.Count();
ViewBag.noLikes = nooflikes;
return Json(ViewBag.noLikes, JsonRequestBehavior.AllowGet);
}
and I have created a Partial View for this:
#if (ViewBag.Message != null)
{
<script>
$(document).ready(function () {
alert('#ViewBag.Message');
});
</script>
}
//to display total likes
<input type="text" id="likes" name="likes" value='#ViewBag.noLikes' readonly="readonly" style="border:none; background-color:transparent; width:20px" /><span style="color:black">likes</span>
and this is the main view in which I am using Ajax.BeginForm()
#using (Ajax.BeginForm("Like", "VOD", new { Id = Model.Id },
new AjaxOptions
{
HttpMethod = "Post",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "likecount"
}))
{
<button type="submit" id="like" value="Like" class=" btn btn-primary btn-xs"> Like <span class="glyphicon glyphicon-thumbs-up" aria-hidden="true"></span> </button>
}
<span id="likecount">
#Html.Partial("Like", new Models.Like())
</span>
Now the issue is that when the page is first loaded it is not displaying total likes, and when I click on like button it returns 1 and when I click like button again it returns 0 but when I refresh the page or when I post back to another page total likes again disappear.
Can anybody help me?
Instead of doing so much code you can do above functionality in simple way.
You will required following to do so,
2 Action Methods,
1. Increment Like Count.
2. Decrease Like Count.
2 Buttons on web page
1. Like Button (Initially visible)
2. DisLike Button (Initially Invisible)
you can create a ajax request on both buttons something like bellow,
$("#btnLike").click(function () {
$.ajax({
type: "POST",
url: "Controller/LikeAction",
data: { /* Your Data */ };
success: function (result) {
// Hide Like Button & Show Dislike Button
},
error: function (error) {
alert("error = " + error);
}
});
});
Same way you can create ajax request for dislike button also. You just need to hide and show buttons.

Ajax paged list pass object to controller

I am working on some advanced searching functionality and I have run into a roadblock. I would like to use AJAX for my search results and use the PagedList additons to handle paging. I have an AdvancedSearchResults action which takes a search filters class and the current page. The issue is how can I pass the search Filters class into this action correctly. I am sure something I am doing just isnt organized correctly as I would think this would be fairly common. I would really appreciate any help. Thanks in advance.
Controller Action:
public ActionResult AdvancedSearchResults(AdvancedSearchFilters searchFilters, int ? page)
{
//DO STUFF
return PartialView("_SearchResults", results);
}
AdvancedSearchResults Filters:
public class AdvancedSearchFilters
{
public string SearchText { get; set; }
public List<string> SelectedTableTypes { get; set; }
public List<Guid> SelectedGenreIds { get; set; }
public List<Guid> SelectedPlatformIds { get; set; }
public int YearMax { get; set; }
public int YearMin { get; set; }
public int RatingMin { get; set; }
public int RatingMax { get; set; }
}
Search Results Partial View:
#model List<SearchResultItem>
#using PagedList
#using PagedList.Mvc
<!-- 15 Per Page -->
<h2>Search Results</h2>
#if (ViewBag.OnePageOfSearchItems.Count > 0)
{
<div class="pagination">
#Html.PagedListPager((IPagedList)ViewBag.OnePageOfSearchItems, page => Url.Action("AdvancedSearchResults", "Search", new { searchFilters = ViewBag.AdvancedSearchFilters, page = page }),
PagedListRenderOptions.EnableUnobtrusiveAjaxReplacing(PagedListRenderOptions.OnlyShowFivePagesAtATime, "#main-results"))
</div>
foreach (var searchResultItem in Model)
{
<a href="#Url.Action(searchResultItem.ResultType, searchResultItem.ResultType, new { id = searchResultItem.ResultId })" class="result">
#if (searchResultItem.ProfileImageLocation != null)
{
<img src="#searchResultItem.ProfileImageLocation" alt="#searchResultItem.ResultName" />
}
<div class="result-info">
<h3>#searchResultItem.ResultName</h3>
<p>#searchResultItem.DisplayText</p>
</div>
</a>
}
<div class="pagination">
#Html.PagedListPager((IPagedList)ViewBag.OnePageOfSearchItems, page => Url.Action("AdvancedSearchResults", "Search", new { searchFilters = ViewBag.AdvancedSearchFilters , page = page }),
PagedListRenderOptions.EnableUnobtrusiveAjaxReplacing(PagedListRenderOptions.OnlyShowFivePagesAtATime, "#main-results"))
</div>
}
else
{
<span>No Matches.</span>
}
Try passing the data to action method in the form of json. Try the below code which pass the json object to action method.
//// construct your json object.
var jsonObj = '{"SelectedTableTypes" : [{"1","2"}]}';
var postData = $.parseJSON(jsonObj);
$.ajax(
{
url: // your URL with Action name AdvancedSearchResults,
data: postData,
cache: false,
dataType: "json",
success: function (result) {
},
error: function (xhr, ajaxOptions, thrownError) {
alert(xhr.status);
alert(thrownError);
}
});

Cascading Dropdown in Mvc3

I am using Mvc3 I have 2 dropdown,BankBranch and city.
On first time load of view i am binding both the dropdon without cascading. then if user select city i want to change bankbranch according to that.
I am confused how i can achieve both the things together.
Thanks in advance.
This blog post should get you on your way. It provides examples for normal form posts, microsoft ajax form post, jquery ajax and others.
http://weblogs.asp.net/raduenuca/archive/2011/03/06/asp-net-mvc-cascading-dropdown-lists-tutorial-part-1-defining-the-problem-and-the-context.aspx
EDIT:
Generalized Code Explanation
Model
public class CascadeModel {
public SelectList<City> Cities { get; set; }
public SelectList<BankBranch> BankBranches { get; set;}
public int CityId { get; set; }
public int BranchId { get; set; }
}
public class Branch {
public int Id { get; set;}
public string Name { get; set; }
}
Controller:
public ActionResult BranchSelector() {
var viewData = new CascadeModel();
viewData.Cities = new SelectList(Repository.GetAllCities(), "Id", "Name", selectedCity);
viewData.BankBranches = new SelectList(Repository.GetBranchesByCity(selectedCity), "Id", "Name", "");
return View(viewData);
}
public JsonResult GetBranches(int id) {
return Json(Repository.GetBranchesByCity(id), JsonRequestBehavior.AllowGet);
}
View:
#model CascadeModel
#Html.DropDownListFor(m => m.CityId, Model.Cities, new { style = "width:250px" })
<br />
#Html.DropDownListFor(m => m.BranchId, Model.BankBranches, new { style = "width:250px" })
<script type="text/javascript">
$(document).ready(function() {
$("#CityId").bind('change', function() {
$.ajax({
url: '/Controller/GetBranches/' + $(this).val(),
success: function(data) {
//Clear the current branch ddl
//Load the new Branch data returned from the jquery call in the branches ddl
}
});
};
});
</script>

Master-Detail Sample Code for MVC 3 Razor (using Ajax for details)

I am looking for sample code to create a master/details with c# mvc 3.
Specifically, I am trying to figure out how to call via ajax the rendering of a partial view. I am able to put the partial view on the form but want to populate it after a user has selected an item from a select list via ajax.
thx
As always you start with the model:
public class MyViewModel
{
public int Id { get; set; }
public string Title { get; set; }
}
public class DetailsViewModel
{
public string Foo { get; set; }
public string Bar { get; set; }
}
then a controller:
public class HomeController : Controller
{
public ActionResult Index()
{
// TODO: don't hardcode, fetch from repository
var model = Enumerable.Range(1, 10).Select(x => new MyViewModel
{
Id = x,
Title = "item " + x
});
return View(model);
}
public ActionResult Details(int id)
{
// TODO: don't hardcode, fetch from repository
var model = new DetailsViewModel
{
Foo = "foo detail " + id,
Bar = "bar detail " + id
};
return PartialView(model);
}
}
and corresponding views.
~/Views/Home/Index.cshtml:
#model IEnumerable<MyViewModel>
<ul>
#Html.DisplayForModel()
</ul>
<div id="details"></div>
<script type="text/javascript">
$(function () {
$('.detailsLink').click(function () {
$('#details').load(this.href);
return false;
});
});
</script>
~/Views/Home/Details.cshtml:
#model DetailsViewModel
#Model.Foo
#Model.Bar
~/Views/Home/DisplayTemplates/MyViewModel.cshtml:
#model MyViewModel
<li>
#Html.ActionLink(Model.Title, "details", new { id = Model.Id }, new { #class = "detailsLink" })
</li>
I have blogged about creating master detail form using asp.net mvc where you can add n child records on clietn side without the need of sending ajax request just to bring the editor fields for child records. it used jquery templates

Resources