Using Antiforgerytoken in AJAX MVC - javascript

I was using antiforgerytoken within my razor view, and it was working fine. Then I moved the same code to AJAX, and it has started giving weird problems.
The AJAX POST request works fine, but the action SendData() which is called from the AJAX has a redirect to a different View (return View("Close");), which does not work anymore. It worked perfectly fine when the SendData() was called from the form directly.
Working code:
#using(Html.BeginForm("SendData", "Controller", FormMethod.Post)) {
#Html.AntiForgeryToken():
}
Not working code:
#using(Html.BeginForm("", "", FormMethod.Post, new
{
id = "__AjaxAntiForgeryForm"
}))
{
#Html.AntiForgeryToken()
}
JS File:
var form = $('#__AjaxAntiForgeryForm');
var token = $('input[name="__RequestVerificationToken"]', form).val();
$.ajax({
type: 'POST',
url: '/Controller/SendData',
data: {
__RequestVerificationToken: token
},
cache: false,
success: function(result) {}
});
The Action SendData() executes fine, but the redirect within this action doesn't work anymore.

I advise you use .serialize() instead of the following line.
var token = $('input[name="__RequestVerificationToken"]', form).val();
It is generic and thus will automatically adapt to any model changes.
For a working example of Antiforgery used alongside Ajax check this answer. The question was asked for MVC3 but it should work perfectly well as long as you're using an MVC version above 3.
The result param in the success: function (result) part of the ajax call will receive whatever was returned by your SendData action. If the SendData action uses a return View([...]); then you will probably get some html code in your result var. You could also return json data as follow return Json([...]).
If you actually want to have a redirect be made by the result of your Ajax call you should return the URL that you want to use as the redirection's target as follow return Content("http://target.url.for.redirect.com"); and then in your success callback, using the location.replace method, do this:
success: function(result)
{
document.location.replace(result);
}
This way the URL returned by the Ajax controller will be used to execute a redirection.
NOTE if you wish to ALWAYS redirect the user after the form is sent you should not use ajax at all ! A regular POST form would be far better suited for the job.

I figured out the problem, as per the comment from Stephen Muecke. The AJAX calls don't allow redirects, as the whole point behind AJAX is to stay on the same page and make a background JS call.

Related

Laravel request()->ajax() triggering on browser back button

Inside my controller I have this function for the route /backups
public function index()
{
$backups = \App\Backup::all();
if(request()->ajax()) {
return $backups;
}
return view('backups.index', compact('backups'));
}
My idea was that if I have my javascript ask for the data then return json if not return html.
This works fine, except when pressing the browser back button to go from lets say /backups/1 to /backups it shows the json.
Is there another function I can use that will only respond to ajax calls from my code and not the browsers?
I'd recommend adding an ajax-only query string parameter to the ajax request, e.g. ?ajax=1.
This way, you can 1. utilise the browser cache, and 2. keep the same Laravel route for both request types.
Make sure your AJAX requests use a different URL from the full HTML documents. Chrome (and most probably Firefox) caches the most recent request even if it is just a partial.
Source:
https://code.google.com/p/chromium/issues/detail?id=108425
Or:
Try setting cache to false
$.ajax({
dataType: "json",
url: url,
cache: false,
success: function (data) {...}
});

Cannot access Rails variable inside Javascript tag

All the other solutions in stackoverflow doesn't seem to work for me so i'm posting my code for assistance. I want to output the variable: #less_per_unit via jquery
Here is my tag inside _form.html.erb:
<script>
$(document).on('keyup', ".input-quantity", function(){
$.ajax({
url: "/so_check_increment",
type: "GET",
data: { quantity: $(this).val(), product_id: $(this).closest('tr').find('.input-product_code').val()}
});
$(this).closest('td').next('td').find('.increment').text('<%== j #less_per_unit%>');
});
</script>
And here is my controller:
def check_increment
#less_per_unit = "testing"
end
I know that the ajax works, i've also set up the routes. If I try binding.pry, I know that rails can find #less_per_unit, but I can't output it with javascript.
This is not working because:
Let us say this form is rendered in action 'new' of controller 'Post', then #less_per_unit needs to be initialised there to use it in the view file of that action which you are using. Where as you are using an AJAX call and during that call, you are defining an instance variable which will definitely be not accessible to the already rendered html file.
So, you need to return JSON data from your check_increment action and receive that data in AJAX call response and then use it.

JQuery Ajax POST throwing an empty error without making the request

I have a function that makes an Ajax request for any anchor. The request method can be GET or POST. In this case, I want to make a POST without using a form but the Ajax request throws an error before even sending the request. The error has the value "error" and all error/failure description variables are "".
function loadPage(url,elem_id,method,data) {
ajaxLoading(elem_id);
$.ajax({
type: method,
url: url,
data: data,
success:function(data){
$("#"+elem_id).html(data);;
},
error:function(request,textStatus,error){
alert(error);
}
});
}
When the function is called the params are these (copied from the js console):
data: "partial=yes"
elem_id: "page"
method: "post"
url: "/projects/2/follow"
As asked, here is the code that calls the loadPage function.
$("body").on("click","a.ajax",function(event) {
var _elem = getDataElem($(this));
var _method = getRequestMethod($(this));
var _partial = getRequestPartial($(this));
handlers.do_request(event,$(this).attr("href"),_elem, _method, _partial);
});
var handlers = (function() {
var obj = {};
obj.do_request = function(event,url,elem_id,method,data) {
event.preventDefault();
loadPage(url,elem_id,method,data);
history.pushState({selector:elem_id,method:method,data:data},null,url);
};
}());
After the failure of the Ajax request, the request is made by default and it responds sucesss. In all I have read, this seems to be a valid way to make a POST request (that doesn't need a form).
Am I doing something wrong in the function? Why is the error information empty?
Thanks
EDIT:
I have been thinking, for a POST from a "form" that function works, when the variable "data" is made with the serialize function (e.g. "var data = $(this).serialize();"). Could it be that the format of the "data" when I make a POST without a "form" is wrong in someway? Maybe the JQuery Ajax function doesn't accept a simple string like "partial=yes" as data when a POST is made. Any thoughts on this?
I just experienced this problem and after an hour or two, thought to try setting cache to false. That fixed it for me.
$.ajax({
url: url,
cache: false,
type: method
});
Unfortunately, when I removed cache again, my request was working as if it had never had a problem. It seems as if setting cache:false made something 'click'.
Oh well.
Just a guess, but in the docs the type parameter is in all caps, i.e. 'POST' and not 'post'.
Try:
function loadPage(url,elem_id,method,dat) {
ajaxLoading(elem_id);
$.ajax({
type: method,
url: url,
data: dat,
success:function(data){
$("#"+elem_id).html(data);;
},
error:function(request,textStatus,error){
alert(error);
}
});
}
I'm wondering if you are running into a problem using a variable named after a keyword. If this doesn't work, try calling loadPage with no arguments and hard coding all of your ajax parameters, just to see if that works.
Could not solve the problem, neither could find the reason why it was happening. Although, I found a way around, by using a hidden empty form instead of an anchor with the method 'POST'. For a form, the function worked nicely.
Thanks for the answers

How can I POST a custom associative without Ajax, or do an HTML redirect from an Ajax POST?

I have two datatables that I am merging together using Javascript and jQuery. I want to POST this data to a Rails controller action, but the results of the action will need to be displayed in another view, and I am a little tired of figuring out how to do a redirect to another action from an AJAX POST (It just refuses to display).
So now my question is, how can I change this code to actually post and do a redirect to another action?
My original code is:
submithash = {}
submithash['standard_id'] = $("#app_standard_id").val()
submithash['apps'] = apps
hash = { type: "POST", url: "create_all", data: submithash }
$.ajax(hash)
This worked GREAT in that it submitted correctly to my Rails controller action, but of course there does not appear to be a clean way to redirect from an Ajax submission and actually physically display an actual page to a user.
I tried:
$form = $("<form>").attr("method", "post").attr("action", "create_all")
$("<input type='hidden'>").attr("name", "standard_id").attr("value", $("#app_standard_id").val()).appendTo($form)
$("<input type='hidden'>").attr("name", "apps").attr("value", apps).appendTo($form)
$form.submit
but of course that refuses to work. It doesn't even do anything, which is a little odd.
If I understand you question correctly you wish to redirect your page to another url when your ajax call to "create_all" completes.
So you can use the success callback function like this:
hash = { type: "POST",
url: "create_all",
data: submithash,
success: function(data){
//Here you can write your redirection code
//this function will be called when ajax completes successfully
window.location = "url"//redirect url;
//or you can also start another ajax
}
};
$.ajax(hash);
Also check out the documentation for jquery.ajax() here
I ended up using this jQuery plugin:
(function($) {
$.extend({
getGo: function(url, params) {
document.location = url + '?' + $.param(params);
},
postGo: function(url, params) {
var $form = $("<form>")
.attr("method", "post")
.attr("action", url);
$.each(params, function(name, value) {
$("<input type='hidden'>")
.attr("name", name)
.attr("value", value)
.appendTo($form);
});
$form.appendTo("body");
$form.submit();
}
});
})(jQuery);
It builds a form on the fly with whatever you pass it, then appends it to the document. Then it does a regular POST (or GET, depending on what you call).

update the div display after jquery post without reloading the page in mvc3

What is the bestHi everyone, a MVC3 newbie here! please take a look at these:
in my View page, i have there:
<div id = "AccounStatusDiv" class="display-field">
#Html.DisplayFor(m => m.AccountStatus)
<input id="btnBool" type="button" class="btnGrid ActStatBtn" value="#(Model.AccountStatus ? "Deactivate" : "Activate")" onclick="ChangeStatus()"/>
</div>
and a script:
<script type="text/javascript">
function ChangeStatus() {
$.post('#Url.Action("SetAccountStatus", "User")',
{ UserName: "#(Model.UserName)",
accountStatus: "#(Model.AccountStatus)" });
// change the display of the AccounStatusDiv elements, or maybe just reload the div element if possible. is it?
}
</script>
while in my Display Template, i have there:
<div id = "AccountStatusDiv" style="display:inline-block;">
<img src="#Html.Custom().ResolveImage((bool)Model ? imgPositive : imgNegative)" alt="#Model" />
<label> #ResourceManager.Localize(resource, display)</label>
</div>
in the controller:
public ActionResult SetAccountStatus(string userName, bool accountStatus)
{
SecurityManager.GetMembershipProvider().SetStatus(userName, !accountStatus);
return AjaxResult.JsonRedirect("/User/ViewUser?username=" + userName);
}
The results are shown only after I reload the page.
I want to display the updated img, label and btnBool elements right after clicking the btnBool without reloading the whole page. What is the best way in such case?
Please post your code suggestions, it would be a great help for me!
Thanks in advance!
You're only using $.post() to send data (request) to the server. AJAX can be two-fold: send a request, and receive the corresponding response. In your code, you're not receiving data back (or, at least, making the necessary arrangements so that you are).
If the SetAccountStatus action of your UserController is set to return some data back (maybe through return Json(), or similar), you can modify the $.post() call to receive it, and have your Javascript react accordingly using a callback function.
var data = {
UserName: "#Model.UserName",
accountStatus: "#Model.AccountStatus"
};
var call = $.post(
'#Url.Action("SetAccountStatus", "User")',
data
);
// set the success callback here
call.success(function (m) {
// the [m] variable contains the data returned by the server
// during the resolution of your call
// this will be called when your AJAX call succeeds,
// and you can use this opportunity to update the HTML DOM with new data
});
this is to event click in button and without refresh page
$("#btnBool").click(function(e){
e.preventDefault();
//to do your code, you can use `$.ajax` to request and get response from server
$.ajax({
url: '#Url.Action("SetAccountStatus", "User")',
type:"GET",
dataType: 'json',
data: { UserName: "#(Model.UserName)",accountStatus: "#(Model.AccountStatus)" },
async:'true',
success:function (data) {
alert(data);
//success to parsing json if you data type of your response is json
}
});
}
you can use web service to send request and get response from server , and to request,get response from server you can use $.ajax() in jquery http://api.jquery.com/jQuery.ajax/

Categories