I have this:
<div id="miniShoppingCartContainer">
#Html.Action("MiniShoppingCart", "ShoppingCart")
</div>
where MiniShoppingCart action returns MiniShoppingCart.cshtml partial view with all the content.
In this partial view I added an ajax call for increasing the quantity of product cart:
#using (Ajax.BeginForm("IncreaseProductQuantity", "ShoppingCart", new { shoppingCartItemId = item.Id }, new AjaxOptions { UpdateTargetId = "miniShoppingCartContainer", InsertionMode = InsertionMode.Replace }))
{
<li>
<input type="submit" class="btn-up" />
</li>
}
which calls a method:
public ActionResult IncreaseProductQuantity(int shoppingCartItemId)
{
//get shopping cart item
var cart = _workContext.CurrentCustomer.ShoppingCartItems
.Where(x => x.ShoppingCartType == ShoppingCartType.ShoppingCart).ToList();
var sci = cart.Where(x => x.Id == shoppingCartItemId).FirstOrDefault();
if (sci == null)
{
return RedirectToRoute("ShoppingCart");
}
//update the cart item
_shoppingCartService.UpdateShoppingCartItem(_workContext.CurrentCustomer,
sci.Id, sci.Quantity + 1, true);
return MiniShoppingCart();
}
Please note that at the end of the method I call the MiniShoppingCart ActionResult which prepares the cart and return the PartialView (as you see at the beginning of the post).
Well, the update of a product is happening fine but the content is not refreshed (or replaced)...
Can you please indicate where I am wrong?
UPDATE:
Doing an inspection with Chrome Dev. Tools I see an error when doing post:
POST http://localhost/ShoppingCart/IncreaseProductQuantity?shoppingCartItemId=11 500 (Internal Server Error)
f.support.ajax.f.ajaxTransport.sendjquery-1.7.1.min.js:4
f.extend.ajaxjquery-1.7.1.min.js:4
ejquery.unobtrusive-ajax.min.js:5
(anonymous function)jquery.unobtrusive-ajax.min.js:5
f.event.dispatchjquery-1.7.1.min.js:3
f.event.add.h.handle.ijquery-1.7.1.min.js:3
2
It's strange to guess what is the problem from this log...Basically, If I make debug I can see that it does all the operations until return PartialView(model); of MiniShoppingCart() method...
Issue found:
>The partial view 'IncreaseProductQuantity' was not found or no view engine supports the searched locations.
So basically, doing return MiniShoppingCart(); from IncreaseProductQuantity method doesn't automatically return the MiniShoppingCart partial view but will still try to return IncreaseProductQuantity partial view which of course does not exists.
Consequently, I have done it like:
var model = PrepareMiniShoppingCartModel();
return PartialView("MiniShoppingCart", model);
Related
I have two models called channels and programs.. in showing the dropdown of channels and all I want is that when I select any channel, the view will show the programs of the specific channel. Problem is when I select any channel, it takes the value of channel and return it to the controller and apply filtering logic and pass the data to the new View..Although the view is executing all values properly on the browser it is not visible.. any help would be grateful.
View Code:
#model SitefinityWebApp.Mvc.Models.Channel
#Html.DropDownListFor(m => m.Title, Model.Items, "Select Channel-", new { #id = "ddl" })
<div id="myddl">
</div>
<script>
$('#ddl').change(function () {
var selectedValue = $('#ddl').val();
$.post('#Url.Action("GetProgramByChannel", "Channels")', { selection : selectedValue }, function (data) {
});
});
</script>
GetProgramByChannel Method Taking the selected value
public ActionResult GetProgramByChannel(string selection)
{
var model = new ProgramsModel();
return View("ProgramsByChannel", model.GetChildItemsOfChannel(selection));
}
ProgramsByChannelView
#model SitefinityWebApp.Mvc.Models.Channel
<div id="ddl">
#foreach (var item in Model.Programs)
{
#Html.DisplayFor(m => item.Title) <br />
#Html.DisplayFor(m => item.ShortDescription) <br />
#Html.DisplayFor(m => item.LongDescription) <br />
}
</div>
Because,with your current code, when user make a selection on the dropdown, you are making an ajax call and the result (the new view result with channels will come as the response for this ajax call) is not being used anywhere.
Instead of doing the ajax call, you can make a new GET request to the action method which will return the view.
$('#ddl').change(function () {
var v = $(this).val();
var url ='#Url.Action("GetProgramByChannel", "Channels")?selection='+v;
window.location.href=url;
});
If you do not want to issue a new GET request,but want to show the result in the same view, then all you have to do is update the DOM with the results coming back from the ajax call.
$('#ddl').change(function () {
var v = $(this).val();
var url ='#Url.Action("GetProgramByChannel", "Channels")';
$.post(url, { selection : v} ,function(result){
$("#myddl").html(result); //update the myddl div
});
});
Now you have to make sure that your action method return a view without layout as you are looking for the partial page result. You can use the PartialView method to do so.
public ActionResult GetProgramByChannel(string selection)
{
var model = new ProgramsModel();
return PartialView("ProgramsByChannel", model.GetChildItemsOfChannel(selection));
}
Also, I see you are overwriting the Id value of dropdown to ddl. Why would you do that ? What is wrong with Title being the Id value of the SELECT element ? If you do not override, the helper will generate the SELECT element with Title as the value of Id and name attributes
I want to show a success message after calling the following ajax.beginform
from Index view
#using (Ajax.BeginForm("Insert", "Home", new AjaxOptions() { UpdateTargetId = "result", HttpMethod = "POST" }))
{
#Html.TextAreaFor(m => m.openion)
}
this is my result div
<div id="result">
</div>
and my controller is
[Httppost]
public ActionResult InforMessage(openionModel usr)
{
return Content("Thanks for adding your openion");
}
but when i try this it is going to another view InforMessage
It is not updating the result div.
There is no Informessage Exist. Still it open a new page with message
"Thanks for adding your openion".How to solve this?
If your redirecting to another page its because you do not have the correct scripts loaded (or have duplicates or have them in the wrong order) so its doing a normal submit.
Ensure you have included (in order)
jquery-{version}.js
jquery.unobtrusive-ajax.js
C# asp.net MVC project: I have my index page with a button in it, I want to press it and update the same page with some results.
Here's some code:
The View: (with a button that calls the getConfig method in the controller)
#{
ViewBag.Title = "Home Page";
}
<form method="get" action="/Home/GetConfig/" >
<input type="submit" value="Get Config WS" />
</form>
<p>
#ViewBag.totalRecords
</p>
The controller:
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Message = "Test webservices";
return View();
}
public void getConfig()
{
string totalRecords = string.Empty;
wsConfig.config_pttClient client = new wsConfig.config_pttClient();
wsConfig.getConfigInput gci = new wsConfig.getConfigInput();
wsConfig.getConfigOutput gco = new wsConfig.getConfigOutput();
gco = client.getConfig(gci);
totalRecords = gco.result.totalRecords.ToString();
ViewBag.totalRecords = totalRecords;
}
I want to press the view's button and show the totalRecords on the same page.
How can I achieve this?
Edit: There might be other solutions, (if you don't mind updating your entire page) but this how I generally do it.
Ok, there are a couple of things that you need to change in order to make it work:
Create a new partial view that contains just the part that you would like to update (and wrap it an element with an id). In this example, let's call it 'Partial_TotalCount'.
This partial view will contain the following code:
<div id="updated">
<p>
#ViewBag.totalRecords
</p>
</div>
Now, change your original view so that it includes the partial view:
#{
ViewBag.Title = "Home Page";
}
<form method="get" action="/Home/GetConfig/" >
<input type="submit" value="Get Config WS" />
</form>
#Html.Partial("Partial_TotalCount", #Model)
Now, update your controller to work with an ajax request. This would make your controller looks like:
public ActionResult Index()
{
ViewBag.Message = "Test webservices";
if (Request.IsAjaxRequest())
{
getconfig();
return PartialView("Partial_TotalCount");
}
return View();
}
Now, you need to be able to submit the page when you click the button. This can be done through javascript:
First your javascript function that will update the contents:
<script type="text/javascript">
function Refresh() {
$.ajax({
url: '/Home/Index',
type: "GET",
dataType: "html",
success: function(data) {
$("#updated").html(data);
},
error: function() { alert('Refreshing error.'); }
});
}
</script>
You just need to add an onclick on your button. And you can remove the form tags from around your form aswell.
Edit: As requested by the questioner, I provide a bit of explanation on the Javascript function itself:
$.ajax means that we are doing an Ajax request. It means that we are doing some asynchronous requests with the server.
Then a couple of parameters are passed:
Url: The url that should be executed. In your example, the code behind the url "Home/GetConfig" get's executed.
Type: The type of submit that you want to do (POST, GET, ...)
dataType: The type we are expecting back from the server.
Success: The piece of javascript that needs to execute when complete. (In this case, update the DIV element with the id "WithCss" with the contents that are received with the url "Home/Getconfig".
Error: A function that is executed when the request failed for some reason.
There are a lot of other parameters you can pass (for example if you need to pass an id, and others.
For more explanation, please look at the original documentation.
Also, consider marking this answer as accepted.
I hope it works.
Try This:
Replace your input button code with the following code :
<input type="submit" id="btnSave" name="BtnSave" value="Get Config WS" />
Then in controller change the whole code for this code:
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Message = "Test webservices";
return View();
}
public ActionResult getConfig()
{
return View();
}
[HttpPost]
public ActionResult getConfig(FormCollection Form)
{
if(Form["BtnSave"]!=null)
{
string totalRecords = string.Empty;
wsConfig.config_pttClient client = new wsConfig.config_pttClient();
wsConfig.getConfigInput gci = new wsConfig.getConfigInput();
wsConfig.getConfigOutput gco = new wsConfig.getConfigOutput();
gco = client.getConfig(gci);
totalRecords = gco.result.totalRecords.ToString();
ViewBag.totalRecords = totalRecords;
}
return View();
}
Hopefully it works...!
Well I have simple ajax form:
This is MyPartialView
#using(Ajax.BeginForm("action", "controller", new AjaxOptions
{
OnBegin = "beginRequest",
OnComplete = "completeRequest",
HttpMethod = "POST",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "div-to-replace"
}, }))
{
<input type="text" id="my-input" />
...
}
This is parent view:
<div id="div-to-replace">
#Html.RenderPartial("MyPartialView")
</div>
In my controller I have:
[HttpPost]
public ActionResult action(Model model)
{
if (ModelState.IsValid)
{
// do staff with model
// return partial view
return PartialView("MyPartialView");
}
// else add error and return json result
return Json(new {error = "invalid data"});
}
And my javascript on ajax complete method:
function completeRequest(data) {
var result = $.parseJSON(data.responseText);
if (result != 'undefined' && result != null && result.error) {
// just display error and not replace all content
// attachModelError is my custom method, it just adds vlaidation-error class to inputs, etc.
attachModelError("my-input", result.error);
return;
}
// or show returned html (depending on returned model form inputs will be modified:
// select box with different items in my case
$('#div-to-replace').html(data.responseText);
}
But the problem is I have empty #div-to-replace if model state is invalid. If model state is ok every thing works fine. If I use different insertion mode it creates duplicates of div's content before or after div.
Summary:
I want different InsertionMode behavior depending on json result. I don't need replace data if (result != 'undefined' && result != null && result.error).
I had to solve this problem once so very long ago. I came up with a simple solution, which today, may not be the best solution but it gets the job done.
My solution involved setting up a controller action that would render just the partial with data that it would need and have my JavaScript request it.
C#
MyController: Controller
{
public ActionResult GetPartialViewAction()
{
return PartialView("mypartialview", new partialViewModel());
}
}
JavaScript
$.ajax({
url: "/my/getpartialaction/"
}).done(function(data) {
$("#partialViewDiv").html(data);
});
HTML
<div id="partialViewDiv"></div>
A better solution would be to use a MVVM/MVC JavaScript library that would allow you to leverage html templates and only have to transmit the data over your ajax solution. I recommend looking into knockout.js or backbone.js for this more accepted pattern.
I have the same problem with the default c# ajax forms. I have a solution what might work.
jQuery:
$(function () {
var ajaxFormSubmit = function () {
var $form = $(this);
var options = {
url: $form.attr("action"),
type: $form.attr("method"),
data: $form.serialize(),
cache: false
}
$.ajax(options).done(function (data) {
data.replaces.each(function (replace) {
$(replace.id).replaceWith(replace.html);
});
});
return false;
};
$("form[data-ajax='true']").submit(ajaxFormSubmit);});
form.cshtml
#using (Html.BeginForm("Create", "Menu", FormMethod.Post, new { data_ajax = "true" }))
{}
model sample
public string Id {get;set;}
public string Html {get;set;}
The last thing you need to do in your controller is return a json result with a list of your model sample, id is target element to update, for the html you must use a render partial / or view as string.
For render view to partial see [question]: https://stackoverflow.com/questions/434453
I have a delete hyperlink shown on the screen:
UsersPartial VIEW:
<%: Ajax.ActionLink("Delete", "Delete", new { id = item.UserID }, new AjaxOptions { HttpMethod = "GET", UpdateTargetId = "tabs-users", InsertionMode = InsertionMode.Replace }, htmlAttributes: new { data_target = "#tabs-users" })%>
This calls a method in my controller
CONTROLLER
[HttpGet]
public PartialViewResult Delete(int id)
{
userManager.DeleteUser(id);
ViewBag.Status = string.Format("User deleted ok, id: {0}", id);
return PartialView("UsersPartial", userManager.GetUsers());
}
In the above code, I return a PartialView, this works. I would like to also display a message at the top of this view, defined above in ViewBag.Status, but I only want it to show this div once this action is taken.
Also note, that my view I am returning to has is strongly typed:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IEnumerable<LMS.Data.User>>" %>
Lastly, the status message I'd like to display is a div that I created into another partial view so I can show it throughout the site.
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<dynamic>" %>
<div id="status" class="statusok">
<%: ViewBag.Status %>
</div>
What's the proper way to do this?
ViewBag.Status will be null until you assign a value to it, so you could just do a check for that in your view then display it:
#if(ViewBag.Status != null)
{
<div id="status" class="statusok">
#ViewBag.Status
</div>
}
In subsequent calls that return the same view, simply set ViewBag.Status to null if you no longer wish it to show.
You cannot return 2 different partial views from a controller action. One approach you might use is to render the first partial to a string and then have your controller action return a JSON result with 2 properties - one containing the HTML partial and the other containing the message to display:
[HttpDelete]
public PartialViewResult Delete(int id)
{
userManager.DeleteUser(id);
return Json(new
{
Partial = RenderPartialViewToString("UsersPartial", userManager.GetUsers()),
StatusMessage = string.Format("User deleted ok, id: {0}", id)
});
}
and then:
<%= Ajax.ActionLink(
"Delete",
"Delete",
new {
id = item.UserID
},
new AjaxOptions {
HttpMethod = "DELETE",
OnSuccess = "onDelete"
},
htmlAttributes: new { data_target = "#tabs-users" }
) %>
and then write the onDelete callback:
function onDelete(result) {
$('#tabs-users').html(result.Partial);
// TODO: instead of alerting display the message wherever you want
// and using whatever plugin you want to make it look pretty
alert(result.StatusMessage);
}
You will also notice that I have used the proper HTTP verb for this task - DELETE. Never use the GET verb to invoke controller actions that are modifying state on your server (such as deleting an entity).