Help with Ajax post to action method - asp.net-mvc

I am a new to MVC an need a little help.
In my view I make an ajax post as below.
function PostCheckedPdf(e) {
var values = new Array();
$('input:checked').each(function () { values.push(this.value); });
$.post("/UnregisteredUserPreview/DownloadPdfInvoice",
{ checkedList: values });
}
This post the values of any checkboxes that are checked inside a third party Grid component (Telerik). The Action method receives the array fine and loops through each value rendering a pdf report and putting the report into a ZipStream which is attached to the Response. After the loop the zipstream is closed and I return View();
When the Action is invoked through the $.post it runs through the action method but nothing happens in the browser.
If I call the Action through an action link (with a couple of hard coded value instead of passing the checked boxes values) the zip file with all the pdfs is downloaded.
What am I doing wrong or how can I post the checked values with an ActionLink?
Thanks in Advance!
Toby.

The difference is that your ActionLink is emitting an <a> tag, which is performing a GET operation. The browser interprets the contents of the response and opens the PDF.
Your jQuery method is performing a POST, but does nothing with the response, and thus silently throws it away in the background.
You need to actually do something with the return contents, like write it out to another window.
var w = window.open('', '', 'width=800,height=600,resizeable,scrollbars');
$.post("/UnregisteredUserPreview/DownloadPdfInvoice",
{ checkedList: values },
function(content){
w.document.write(content);
w.document.close(); // needed for chrome and safari
});

You are making an Ajax call to the server there and client side code should receive the returned result which seems that you are not doing there. It should be something like below :
$.ajax({
type: 'POST'
url: '/UnregisteredUserPreview/DownloadPdfInvoice',
data: { checkedList: values },
success: function (r) {
alert(r.result);
}
});
And assume that your controller is like below :
public ActionResult DownloadPdfInvoice() {
//do you stuff here
return Json(new { result = "url_of_your_created_pdf_might_be_the_return_result_here"});
}
NOTE
If you are posting your data with anchor tag, it is better to
prevent the default action of this tag so that it won't do anything
else but the thing you're telling it to do. You can do that by adding the
following code at the end of your click event function :
$("#myLink").click(function(e) {
//do the logic here
//ajax call, etc.
e.preventDefault();
});
Have a look at the below blog post as well. It might widen your thoughts :
http://www.tugberkugurlu.com/archive/working-with-jquery-ajax-api-on-asp-net-mvc-3-0-power-of-json-jquery-and-asp-net-mvc-partial-views

Related

Use ValidateAntiForgeryToken with JQGrid in asp.net MVC?

In a hybrid asp.net web forms/mvc 5.2.6 application, using JQuery.jqGrid v4.4.4, I'm struggling to discover a way to use the ValidateAntiForgeryToken attribute on the Controller method that jqGrid posts to when fetching its data.
The grid is read-only. The "datatype" is "json" and the "mtype" is "POST". I've tried simply appending the value of the __RequestVerificationToken hidden input to the data that gets posted back to the Controller, but that does not work; the site simply throws a missing antiforgery token exception.
I notice that when one wants to make an $.ajax post of json data to a Controller method one can pass the __RequestVerificationToken in the "headers" parameter. While the jqGrid makes an $.ajax call behind the scenes, unfortunately it does not have a headers parameter.
I've found examples on SO where one can pass the token via the editData parameter (such as this: JQGrid able to pass ValidateAntiForgeryToken through the main CRUD controls?), but my grid is read-only, and in any case I want to enforce the token when the user enters search criteria and then clicks a button to fill the grid.
Is there any way to use the ValidateAntiForgeryToken when filling a jqgrid?
You can include postData parameter with __RequestVerificationToken property defined as the following function:
postData: {
__RequestVerificationToken: function () {
return jQuery("input[name=__RequestVerificationToken]").val();
}
}
It will add __RequestVerificationToken parameter to all request sent to the server during filling the grid.
Oleg's answer was the correct answer for me, but I also bumbled across this broader-brush solution from https://github.com/VahidN/jqGrid-Samples/blob/master/jqGrid04/jqGrid04/Views/Home/Index.cshtml, which adds the verification token to every ajax POST:
$(document).ajaxSend(function (elm, xhr, s) {
let securityToken = $('[name=__RequestVerificationToken]').val();
if (s.type === 'POST' && typeof securityToken != 'undefined') {
if (s.data.length > 0) {
s.data += "&__RequestVerificationToken=" + encodeURIComponent(securityToken);
}
else {
s.data = "__RequestVerificationToken=" + encodeURIComponent(securityToken);
}
}
});

How to receive Open/Save file dialog after ajax-form post with ASP.NET MVC and jQuery

I want to be able to receive open/save dialog for a pdf file being returned from controller without using 'Html.Beginform' in ASP.NET MVC. I´m using 'Ajax.Beginform' since I can register events to fire OnBegin and OnComplete (which I think I can´t do when using Html.Beginform, or is it?).
I want to state that the problem is not creating and receiving the file from the server when using 'Html.Beginform' because that works fine, but without the events I want to use. I´m using 'Ajax.Beginform' and the file is being returned from the controller but nothing happens after that client side.
My cshtml
#using (Ajax.BeginForm("CreatePdf", "Print", null, new AjaxOptions() { LoadingElementId = "printLoading", OnSuccess = "printPageComplete"}, new { id = "exportForm" }))
{
//Stuff abbreviated
<input type="button" onclick="onPrint()" />
}
My jQuery
function onPrint()
{
//Stuff abbreviated
$("#exportForm").submit();
}
function printPageComplete(result)
{
//this 'result' variable is obviously holding the file from the controller
//stuff abbreviated
//TODO: I need to open file dialog here
}
My Controller
[HttpPost]
public ActionResult CreatePdf(FormCollection collection)
{
//Stuff abbreviated
return File(thePdf, _mimeTypes[ExportFormat.Pdf], "thePdf.pdf")
}
As you can see I´ve managed to get this far as in the printPageComplete function but I´m not sure where to go from here. Should I continue using the ajax form or should I stick with the html form and try to find other way to fire the events I so sorely need to use?
Perhaps I´m going about this all wrong and your help would be very well appreciated.
You can post a form without using Ajax.BeginForm. It is more work, but gives you more flexibility:
$('#exportForm').submit(function (e){
e.preventDefault();
//Do any validation or anything custom
$.ajax({
//set ajax settings
success: function(){
// Handle the success event
}
});
});

Replace partialview after action in ASP.Net MVC

I'm still quite new to ASP.NET MVC and wonder how-to achieve the following:
On a normal view as part of my master page, I create a varying number of partial views with a loop, each representing an item the user should be able to vote for. After clicking the vote-button, the rating shall be submitted to the database and afterwards, the particular partial view which the user clicked shall be replaced by the same view, with some visual properties changed. What is the best practice to achieve this?
Here's how I started:
1. I defined the partial view with an if-sentence, distinguishing between the visual appearance, depending on a flag in the particular viewmodel. Hence, if the flag is positive, voting controls are displayed, if it's negative, they're not.
I assigned a Url.Action(..) to the voting buttons which trigger a controller method. In this method, the new rating is added to the database.
In the controller method, I return the PartialView with the updated ViewModel. UNFORTUNATELY, the whole view get's replaced, not only the partial view.
Any suggestions how-to solve this particular problem or how-to achieve the whole thing would be highly appreciated.
Thanks very much,
Chris
Trivial (but by all means correct and usable) solution to your problem is Ajax.BeginForm() helper for voting. This way you change your voting to ajax calls, and you can easily specify, that the result returned by this call (from your voting action, which will return partial view with only 1 changed item) will be used to replace old content (for example one particular div containing old item before voting).
Update - 11/30/2016
For example:
#using (Ajax.BeginForm("SomeAction", "SomeController", new { someRouteParam = Model.Foo }, new AjaxOptions { UpdateTargetId = "SomeHtmlElementId", HttpMethod = "Post" }))
ASP.NET MVC is a perfect framework for this kind of needs. What I would do if I were in your possition is to work with JQuery Ajax API.
Following blog post should give you a hint on what you can do with PartialViews, JQuery and Ajax calls to the server :
http://www.tugberkugurlu.com/archive/working-with-jquery-ajax-api-on-asp-net-mvc-3-0-power-of-json-jquery-and-asp-net-mvc-partial-views
UPDATE
It has been asked to put a brief intro so here it is.
The following code is your action method :
[HttpPost]
public ActionResult toogleIsDone(int itemId) {
//Getting the item according to itemId param
var model = _entities.ToDoTBs.FirstOrDefault(x => x.ToDoItemID == itemId);
//toggling the IsDone property
model.IsDone = !model.IsDone;
//Making the change on the db and saving
ObjectStateEntry osmEntry = _entities.ObjectStateManager.GetObjectStateEntry(model);
osmEntry.ChangeState(EntityState.Modified);
_entities.SaveChanges();
var updatedModel = _entities.ToDoTBs;
//returning the new template as json result
return Json(new { data = this.RenderPartialViewToString("_ToDoDBListPartial", updatedModel) });
}
RenderPartialViewToString is an extension method for controller. You
need to use Nuget here to bring down a very small package called
TugberkUg.MVC which will have a Controller extension for us to convert
partial views to string inside the controller.
Then here is a brief info on how you can call it with JQuery :
var itemId = element.attr("data-tododb-itemid");
var d = "itemId=" + itemId;
var actionURL = '#Url.Action("toogleIsDone", "ToDo")';
$("#ajax-progress-dialog").dialog("open");
$.ajax({
type: "POST",
url: actionURL,
data: d,
success: function (r) {
$("#to-do-db-list-container").html(r.data);
},
complete: function () {
$("#ajax-progress-dialog").dialog("close");
$(".isDone").bind("click", function (event) {
toggleIsDone(event, $(this));
});
},
error: function (req, status, error) {
//do what you need to do here if an error occurs
$("#ajax-progress-dialog").dialog("close");
}
});
There needs to be some extra steps to be taken. So look at the blog post which has the complete walkthrough.

ASP.NET MVC multiple forms, staying on same page

I have forms located in multiple areas in my layout page (not nested).
I have a partial view which performs a post to controller action.
What action result do I return in that post to keep the user on the current page?
Is jquery/ajax my only option? I would rather a solution that didn't depend on javascript, maybe even a solution that degrades nicely.
You can use the Request.Referrer property to see what page the user has come from and then just use that to redirect them back there.
This does introduce other issues, e.g. losing ModelState, so you'll have to design for that. Also note that some users can block sending referrer information in their requests to the server - so the Referrer property can be null.
I would recommend using AJAX and then falling back on this.
You just need to do a RedirectToAction("") back to your main view.
To post a form without submitting the whole page, which refreshes the browser, you need to use Ajax/jQuery. The degraded solution is to submit the whole page like you would with a normal form.
Here's how I do it with jQuery.
Html:
<div id="RequestButtonDiv">
<button id="RequestButton" name="Request" type="button">Request</button>
</div>
This calls AddToCart on my Request controller when the RequestButton button is clicked. The response is placed inside the RequestButtonDiv element.
<script type="text/javascript">
$(document).ready(function () {
$('#RequestButton').click(function (event) {
$('#RequestButton').text('Processing...');
$('#RequestButton').attr('disabled', true);
submitRequest();
});
});
function submitRequest() {
$.ajax({
url: '<%: Url.Action("AddToCart", "Request", new { id = Model.RowId, randomId = new Random().Next(1, 999999) } ) %>',
success: function (response) {
// update status element
$('#RequestButtonDiv').html(response);
}
});
}
</script>
Controller action:
public ActionResult AddToCart(int id)
{
var user = AccountController.GetUserFromSession();
user.RequestCart.AddAsset(id);
return View("~/Views/Assets/Details_AddToCart.ascx");
}
The controller returns a partial view. You could also return Content("some stuff") instead.
Holler if you have questions or need more detail.

Loading Page for ASP.Net MVC

I'm using ASP.Net MVC to create a web site which needs to do some processing (5 - 10 seconds) before it can return a view to the user. Rather than leaving the user staring at the glacial progress bar I'd like to show some sort of "Please Wait/We'll be right back" animated gif to keep them interested.
Does anyone know a good approach to achieving this?
(I found this answer but its not quite what I need, this uses jQuery to fetch data once the view has been returned. I'd like to display the "Please Wait" while they're waiting for the view to appear)
Thanks
I think the solution you referenced will work for you. You just need to have your initial controller action return right away with the "please wait message", then have the AJAX call do the actual retrieval of the contents based on your processing. If the request really takes 5-10 seconds you may also need to adjust the timeout value on the AJAX request so that it is able to complete. I don't know what the default timeout is but is may be less than what you need.
EDIT Example:
View code:
<script type="text/javascript">
$(document).ready( function() {
$.ajax({
type: "POST",
url: '<$= Url.Action("GetSlowData","Controller") %>',
data: 'id=<%= ViewData["modelID"] %>',
timeout: 15000, // wait upto 15 secs
success: function(content){
$("#container").html(content);
}
});
});
</script>
...
<div id="#container">
Please wait while I retrieve the data.
</div>
Controller
public ActionResult ViewMyData( int id )
{
ViewData["modelID"] = id;
return View();
}
[AcceptVerbs( HttpVerbs.Post )]
public ActionResult GetSlowData( int id )
{
var model = ... do what you need to do to get the model...
return PartialView(model);
}
You'll also need a partial view (ViewUserControl) that takes your model and renders the view of the model. Note that this isn't complete -- you'll need to add error handling, you may want to consider what happens if javascript isn't enabled, ...

Resources