I am updating product Quantity by Update button, after clicking on update button page is reloading, instead of reloading that page i want to update that "cartUpdatePanel" table area only by Ajax
My View is
using (Html.BeginRouteForm("ShoppingCart", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<table id="cartUpdatePanel" class="table_class" cellpadding="0" cellspacing="0">
#foreach (var item in Model.Items)
{
<tr style="background: #f3f3f3;">
<td>
<input type="submit" name="updatecartproduct#(item.Id)" value="Update Cart" id="updatecartproduct#(item.Id)" />
</td>
</tr>
}
}
My Controller action is, by which i am updating Product Quantity
[ValidateInput(false)]
[HttpPost, ActionName("Cart")]
[FormValueRequired(FormValueRequirement.StartsWith, "updatecartproduct")]
public ActionResult UpdateCartProduct(FormCollection form)
{
if (!_permissionService.Authorize(StandardPermissionProvider.EnableShoppingCart))
return RedirectToRoute("HomePage");
//get shopping cart item identifier
int sciId = 0;
foreach (var formValue in form.AllKeys)
if (formValue.StartsWith("updatecartproduct", StringComparison.InvariantCultureIgnoreCase))
{
sciId = Convert.ToInt32(formValue.Substring("updatecartproduct".Length));
break;
}
//get shopping cart item
var cart = _workContext.CurrentCustomer.ShoppingCartItems
.Where(x => x.ShoppingCartType == ShoppingCartType.ShoppingCart).ToList();
var sci = cart.Where(x => x.Id == sciId).FirstOrDefault();
if (sci == null)
{
return RedirectToRoute("ShoppingCart");
}
//update the cart item
var warnings = new List<string>();
foreach (string formKey in form.AllKeys)
if (formKey.Equals(string.Format("itemquantity{0}", sci.Id), StringComparison.InvariantCultureIgnoreCase))
{
int newQuantity = sci.Quantity;
if (int.TryParse(form[formKey], out newQuantity))
{
warnings.AddRange(_shoppingCartService.UpdateShoppingCartItem(_workContext.CurrentCustomer,
sci.Id, newQuantity, true));
}
break;
}
//updated cart
cart = _workContext.CurrentCustomer.ShoppingCartItems.Where(x => x.ShoppingCartType == ShoppingCartType.ShoppingCart).ToList();
var model = PrepareShoppingCartModel(new ShoppingCartModel(), cart, true, false, true);
//update current warnings
//find model
var sciModel = model.Items.Where(x => x.Id == sciId).FirstOrDefault();
if (sciModel != null)
foreach (var w in warnings)
if (!sciModel.Warnings.Contains(w))
sciModel.Warnings.Add(w);
return View(model);
}
How i will achieve to update "cartUpdatePanel" table area after clicking on update button by ajax
Thanx in Advance
Please consider using Ajax.BeginForm helper to create the form. You can use AjaxOptions to specify callback code to capture server output and do whatever you want (including injecting it to a div, table, field set ..)
Using the Ajax.BeginForm is very easy
#using (Ajax.BeginForm(
"name_of_the_action",
new AjaxOptions {
OnSuccess = "processServerResp",
HttpMethod = "POST"},
new {enctype="multipart/form-data"})
){
// rest of the form code
}
Now using javascript, implement processServerResp as a function which takes a single parameter. This parameter will contain what ever values passed from the server to the client. Assuming the server is returning html, you can use the following code to inject it into a container with the id of id_fo_the_div
function processServerResp(serverData){
$(‘#id_fo_the_div’).html(serverData);
// or inject into a table ..
}
You can tap into other interesting features provided by AjaxOptions and do very interesting things.
A good article on Ahax.BeginForm http://www.blackbeltcoder.com/Articles/script/using-ajax-beginform-with-asp-net-mvc
Happy coding
Related
It seems like the PagedList.Core does not contain the extension method for Html helper, so I cannot use the code below:
#Html.PagedListPager(Model, page => Url.Action("Index", new { page }), PagedListRenderOptions.MinimalWithItemCountText)
I was able to successfully implement the paging in previous version of MVC, but it does not work in ASP.Net Core. Below I have attached IL Dasm reference. Am I missing something, or is there any other way to implement that?
PagedList.Mvc:
PagedList.Core.Mvc:
To use PagedList in .Net Core 3.0 we will use https://github.com/dncuug/X.PagedList
Open NuGet Package Manager Install X.PagedList.Mvc.Core
_ViewImports.cshtml
#using X.PagedList.Mvc.Core;
#using X.PagedList;
#using X.PagedList.Mvc.Common
BrandController.cs
public ActionResult Index(int? page)
{
var pageNumber = page ?? 1;
var pageSize = 10; //Show 10 rows every time
var brands = this._UoW.BrandsRepository.GetAll().ToPagedList(pageNumber,pageSize);
return View(brands);
}
Index.cshtml
Change
#model IEnumerable<Stock.Data.Models.Brands>
to
#model IPagedList<Stock.Data.Models.Brands>
Change every
#Html.DisplayNameFor(model => model.BrandName)
To
#Html.DisplayNameFor(model => model.First().BrandName)
At the the end of your html table add paging numbers like
<div class="pull-right">
#Html.PagedListPager((IPagedList)Model, page => Url.Action("Index",
new
{
page
}),
new PagedListRenderOptionsBase
{
LiElementClasses = new string[] { "page-item" },
PageClasses = new string[] { "page-link" },
Display = PagedListDisplayMode.IfNeeded
})
</div>
If you make search or using other querystring you have to do something like that:
BrandController.cs
public ActionResult Index(string search,int? page)
{
var pageNumber = page ?? 1;
var pageSize = 10; //Show 10 rows every time
var brands = this._UoW.BrandsRepository.GetAll().Where(b =>
b.BrandName.Contains(search) ||
search == null).ToPagedList(pageNumber, pageSize);
return View(brands);
}
Index.cshtml
At the the end of your html table add paging numbers like
<div class="pull-right">
#Html.PagedListPager((IPagedList)Model, page => Url.Action("Index",
new
{
page,
search = Context.Request.Query["search"]
}),
new PagedListRenderOptionsBase
{
LiElementClasses = new string[] { "page-item" },
PageClasses = new string[] { "page-link" },
Display = PagedListDisplayMode.IfNeeded
})
</div>
For best performance use
.ToPagedList with IQueryable
so you will return only 10 rows from the database every time not the whole rows
Use
public IQueryable<T> GetAll()
{
return this._DbSet;
}
with
this._UoW.BrandsRepository.GetAll().ToPagedList(pageNumber,pageSize);
Do not use .ToList()
this._UoW.BrandsRepository.GetAll().ToList().ToPagedList(pageNumber,pageSize);
Do not use
public IEnumerable<T> GetAll()
{
return this._DbSet;
}
with
this._UoW.BrandsRepository.GetAll().ToPagedList(pageNumber,pageSize);
I should follow the Instructions of the new version, it is a little different from previous version. I was able to implement the paging with the following code changes:
Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
}
_ViewImports.cshtml:
#addTagHelper *, PagedList.Core.Mvc
And finally to use it, we don't use Html tag helper anymore in .Net Core:
<pager class="pager-container" list="#Model" options="#PagedListRenderOptions.TwitterBootstrapPager" asp-action="Index" asp-controller="ControllerName" />
Include X.PagedList.Mvc.Core
nuget in your project. Then add this to your view:
#using X.PagedList.Mvc.Core
Then this should work:
#Html.PagedListPager(Model, page => Url.Action("Index", new { page }))
I am playing around with some ajax, and have experienced a very odd and to me illogical bug.
I am displaying a list of events, wrapped in a form, in a table. Each event has a unique ID (EventID). This is submitted to the action when a button is pressed.
A div surrounding the table is now updated with the partialview that the action has returned.
The problem
When the view is reloaded, all the HiddenFields that contains the field EventID, now cointains the same EventID as. the one that was submitted to the action
I have tried placing a breakpoint in the view, to see what value is put in the HiddenField. Here is see that the correct id is actually set to the field. but when the page updates, all the hiddenfields contains the same eventid as the one originally submitted to the action.
The partialview: _Events
#model SeedSimple.Models.ViewModelTest
<table class="table table-striped table-bordered table-condensed">
#foreach (var item in Model.events)
{
#using (Ajax.BeginForm("AddAttendantToEvent", "MadklubEvents", new AjaxOptions()
{
HttpMethod = "post",
UpdateTargetId = "tableevents"
}))
{
#Html.Hidden("EventID", item.MadklubEventID);
<input type="submit" value="Join!" id="join" class="btn" />
}
#using (Ajax.BeginForm("RemoveAttendantFromEvent", "MadklubEvents", new AjaxOptions()
{
HttpMethod = "post",
UpdateTargetId = "tableevents"
}))
{
#Html.Hidden("EventID", item.MadklubEventID);
<input type="submit" value="Leave" class="btn" />
}
}
</table>
AddAttendantToEvent Action:
[HttpPost]
[Authorize]
public ActionResult AddAttendantToEvent(int EventID)
{
if (ModelState.IsValid)
{
var uow = new RsvpUnitofWork();
var currentUser = WebSecurity.CurrentUserName;
var Event = uow.EventRepo.Find(EventID);
var user = uow.UserRepo.All.SingleOrDefault(u => u.Profile.UserName.Equals(currentUser));
user.Events.Add(Event);
Event.Attendants.Add(user);
uow.Save();
ViewModelTest viewmodel = new ViewModelTest();
viewmodel.events = madklubeventRepository.AllIncluding(madklubevent => madklubevent.Attendants).Take(10);
viewmodel.users = kitchenuserRepository.All;
return PartialView("_Events", viewmodel);
}
else
{
return View();
}
}
How all the input fields look after having submitted EventID 4 to the action
<input id="EventID" name="EventID" type="hidden" value="4">
I am suspecting, this is due to some side-effects from the ajax call, that i am unknown to.
Any enlightentment on the subject would be much appreciated :)
I ask a similar question here
So I add Some OnComplete Functions and Id to Ajax Forms, And there is:
This is My View:
#foreach(var item in Model) {
<tr id="TR#(item.Id)">
#{Html.RenderPartial("_PhoneRow", item);}
</tr>
}
_PhoneRow:
#model PhoneModel
#using(Ajax.BeginForm("EditPhone", new { id = Model.Id }, new AjaxOptions {
UpdateTargetId = "TR" + Model.Id,
OnComplete = "OnCompleteEditPhone"
}, new { id = "EditAjaxForm" + Model.Id})) {
<td>#Html.DisplayFor(modelItem => Model.PhoneNumber)</td>
<td>#Html.DisplayFor(modelItem => Model.PhoneKind)</td>
<td><input type="submit" value="Edit" class="CallEditPhone" id="edit#(Model.Id)" /></td>
}
Controller:
public ActionResult EditPhone(long Id) {
//Get model by id
return PartialView("_EditPhoneRow", model);
}
public ActionResult SavePhone(PhoneModel model) {
//Save Phone, and Get Updatet model
return PartialView("_PhoneRow", model);
}
_EditPhoneRow
#model PhoneModel
#using(Ajax.BeginForm("SavePhone", new { id = Model.Id }, new AjaxOptions {
UpdateTargetId = "TR" + Model.Id,
OnComplete = "OnCompleteSavePhone"
})) {
<td>#Html.EditorFor(modelItem => Model.PhoneNumber)</td>
<td>#Html.EditorFor(modelItem => Model.PhoneKind)</td>
<td><input type="submit" value="Save" class="SaveEditPhone" id="save#(Model.Id)" /></td>
}
And Oncomplete Scripts:
function OnCompleteEditPhone() {
$('input.SaveEditPhone').click(function () {
var id = $(this).attr("id").substring(4);
$('form#SaveAjaxForm' + id).trigger('submit');
});
}
function OnCompleteSavePhone() {
$('input.CallEditPhone').click(function () {
var id = $(this).attr("id").substring(4);
$('form#EditAjaxForm' + id).trigger('submit');
});
}
So Click Edit Worked perfect, Then Click Save Worked good also, But in second time when i click the Edit Button I have an Error in Post Action I copy the Firebug console here:
http://Mysite/members/editphone/7652 200 OK 582ms
http://Mysite/members/savephone/7652 200 OK 73ms
http://Mysite/members/editphone/7652 500 internal server error 136ms
<title>The view 'EditPhone' or its master was not found or no view engine supports the searched locations. The following locations were searched: ...
So where is the problem? If I remove OnCompleteSavePhone The Edit button for second time not worked, and with this function I have an error that not make any sense, How Can I fix it? I actually load partial views by Ajax, And need the buttons of this views worked correctly, at first every thing is fine but after Ajax result They don't, I think to add some Oncomplete functions, but there is an error also.
Your previous question is answered now. You had broken markup. As a consequence of this you no longer need to care about any OnComplete events and doing some auto triggers, form submissions and stuff. This will be handled by the Ajax.BeginForm infrastructure automatically for you.
I have 2 dropdownlists on the Index page, and I wish to pass the id's of the selected items to the Create Page, so that I can populate the 2 dropdownlists on the Create page the same as the Index page.
Can you please suggest how I can do this?
At the moment I have this in the Index View :-
#Html.ActionLink("Create New", "Create", new { LeagueId = "ddlLeagues" }, new { ClubId = "ddlClubs" })
And then in the Controller :-
public ActionResult Create(int LeagueId, int ClubId)
{
var _LeagueID = LeagueId;
var _ClubID = ClubId;
Any help is very much appreciated!
Thanks
You can do it as described in this post:
ActionLink routeValue from a TextBox
you basically need to wrap your dropdowns with a form that routes to the create function, and the submit will take care of passing those values to your controller because they will be in the form data:
#using(Html.BeginForm("Create", "Footballer", FormMethod.Get))
{
#Html.DropDownList("LeagueId", Model.Leagues)
#Html.DropDownList("ClubId", Model.Clubs)
<input type="submit" value="Create"/>
}
If you are using a strongly typed model that has Properties for LeagueId and ClubId then use:
#Html.DropDownListFor(m => m.LeagueId, Model.Leagues)
#Html.DropDownListFor(m => m.ClubId, Model.Clubs)
Model.Clubs and Model.League are the IEnumerables that you will use to populate your dropDowns ofcourse
in your controller make sure you have the following:
[HttpGet]
public ActionMethod Create(int LeagueId, int ClubId)
{
//return your Create View
}
[HttpPost]
public ActionMethod Create(FormCollection data)
{
//Perform the create here
}
You can add a route into the application RegisterRoutes :
routes.MapRoute(
"CreateFootBallerWith2ComboOptions",
"{controller}/{action}/{LeagueId}/{ClubId}",
new { controller = "Footballer", action = "Create", LeagueId = -1, ClubId = -1 } // Default Values
);
You can then use what Bassam suggest with the ActionLink which is a Html Helper.
#Html.ActionLink("Create New", "Create",
new { LeagueId = 1, ClubId = 213 });
or use directly from the browser using :
localhost:7246/Footballer/Create/1/5
Requirment: I have a drop down and a table on my cshtml page. The drop down displays a list of vendors and the details corresponding to selected vendor are displayed in table. I am submitting the form using jquery when the value of the drop down changes.
Problem: How to cath selected value of drop down in controller?
Code:
#Html.DropDownList("VendorList", new SelectList(Model.vendorList, "vendorId", "vendorName"))
#using (Html.BeginForm("VendorDetails", "VendorLookUp", FormMethod.Post, new { id = "vendorDetailsForm" }))
{
<div class="margin-10-top" >
<table id= "VendorDetail" class="VendorDetail">
........ details of vendor.........
</table>
</div>
}
<script type="text/javascript" charset="utf-8">
$(document).ready(function () {
$('#VendorList').change(function () {
$('#vendorDetailsForm').submit();
});
});
</script>
the code in my controller is:
[AcceptVerbs("POST")]
public ActionResult SearchResult(FormCollection collection)
{
try
{
string vendorName = collection["searchItem"].ToString();
vendorName = vendorName.Trim();
List<Vendor> vendorList = Queries.compiledVendorQuery(dbContext, vendorName).ToList<Vendor>();
if(vendorList.Count() == 0)
return View("EmptySearch");
Vendor selectedVendor = vendorList[0];
VendorDetails vendorDeatils = Queries.compiledVendorDetailsQuery(dbContext, selectedVendor.vendorId.ToString()).FirstOrDefault();
VendorResult vendorResult = new VendorResult();
vendorResult.vendorList = vendorList;
vendorResult.vendorDetails = vendorDeatils;
return View(vendorResult);
}
catch (Exception e)
{
return View("EmptySearch");
}
}
[AcceptVerbs("POST")]
public ActionResult VendorDetails(FormCollection collection)
{
**here comes the control after postback
require value of the selected item**
Vendor selectedVendor = ??
VendorDetails vendorDeatils = Queries.compiledVendorDetailsQuery(dbContext, selectedVendor.vendorId.ToString()).FirstOrDefault();
VendorResult vendorResult = new VendorResult();
vendorResult.vendorDetails = vendorDeatils;
return View(vendorResult);
}
Since you're not really using the FormCollection, you could just use an int (or whatever the ID is on your model) in your action method:
[HttpPost]
public ActionResult VendorDetails(int vendorId = 0)
{
Vendor selectedVendor = // Load from your data source using vendorId
... // Do the rest of your work
}
In your HTML, move your #Html.DropDownListFor() into your form, rename it to the argument name, then submit the form as normal. Since the display doesn't seem to have any affect on what gets sent to the server, I would pull this out and just leave the #Html.DropDownListFor() in the form:
#using (Html.BeginForm("VendorDetails", "VendorLookUp", FormMethod.Post, new { id = "vendorDetailsForm" }))
{
#Html.DropDownList("vendorId", new SelectList(Model.vendorList, "vendorId", "vendorName"))
}
<div class="margin-10-top" >
<table id= "VendorDetail" class="VendorDetail">
........ details of vendor.........
</table>
</div>
<script type='text/javascript'>
$(document).ready(function () {
$('#vendorId').change(function () {
$('#vendorDetailsForm').submit();
});
});
</script>
Edit
Take a look at this article about MVC's model binding for an idea of how vendorId gets injected from the submitted form. Basically, the binder will match property names with the name attribute (by default) to your model. In this case, our model is just an int.