ASP MVC 4 Ajax.ActionLink for delete using AntiForgeryToken - asp.net-mvc-4

I have a number of index pages where the row has an actionlink like so
#Ajax.ActionLink("Delete", "Delete", "AdverseEvent", new { id = Model.AdverseEventId }, new AjaxOptions { HttpMethod = "Post",OnSuccess = "rowDeleted", LoadingElementId="ajaxRequest_processing", Confirm = String.Format("Are you sure you want to delete adverse event for participant {0} at {1} ?", Model.ParticipantId, Model.EventTime) }, new { #class = "deleteAction" })
An actionlink is a great way to use progressive enhancement, because of course there is also a delete action, with get and post methods to perform the delete for those with javascript disabled.
I need to add an AntiForgeryToken. For an Ajax.BeginForm helper, Jon White's code works beautifully:
$.ajaxPrefilter(function (options, localOptions, jqXHR) {
var type = options.type.toLowerCase();
if (type === 'post') {
var token = GetAntiForgeryToken();
jqXHR.setRequestHeader(token.name, token.value);
}
});
When this gets executed within an actionlink, I assume because the index table is not wrapped in a form, I get the error message:
The required anti-forgery form field "__RequestVerificationToken" is not present
So i could wrap the whole table in a form posting back to the delete action, but this is then not very neat if I want to use other ajax.actionlinks to different actions within the table. I could wrap each actionlink in its own form, each with its own antiforgery token, but this is a significant amount of extra markup, and will leave dozens of elements on the page with identical values and name. The other option would be to use the ActionLink OnBegin method to wrap the button in a form, but the unobtrusive ajax library does not seem to pass any reference to the element causing the ajax get/post (foolishly in my opinion - you can upvote this issue on codeplex).
Any thoughts on a neat solution? Thank you.

You can add the token into the page and then use Ajax to send the field over in another call.
see How to include the #Html.AntiForgeryToken() when deleting an object using a Delete link

Related

get request url after AJAX request

I have a search page with link Search?params but any subsequent search requests are made via Ajax forms using Asp.Net. It makes a request to an action with a different name like InstantSearch?params but in the browser I see Search?params.
From this page I have a link to another page and I need to save the Url to return back to this page.
But if I had an AJAX request, Request.Url returns InstantSearch?params, not the link from browser address bar. And the action from this link returns only a Partial View, so when it returns to the previous URL the page is messed up.
How do I get the link of the previous page, from the browser address bar in Asp.Net, not the actual last requested URL?
While searching we are loading masonry containers like this:
$("#main-content-container").load("/Kit/InstantSearch?" + parameters, function() {
$('#mason-container').imagesLoaded(function() {
$('#mason-container').masonry({
itemSelector: '.kit-thumb-container',
columnWidth: 210,
isFitWidth: true,
gutter: 10
});
});
});
Then I'm calling foundation Joyride on same page and need to pass current page URL to return back. Joyride calls onload of the page under this link:
#Html.ActionLink("Go to kit details help", "OrderPageHelp", "Kit", new { returnUrl = Request.Url }, new { #style = "font-size:16px;" })
The needed page return Url is Kit/Search?params, but Request.Url returns that last request when loading masonry with Kit/InstantSearch?params.
How can I pass the needed Url without hard-coding it?
So this ones a bit old but I found myself in a similar situation recently and found a quick work around. Posting it in case any one's interested.
You can solve this problem by taking advantage of the TempData class.
Temp Data can be used to store data in between requests. The information will remain as long as the session is active, until you retrieve the data again.
So when the user first loads the page, before the ajax method is triggered, store the data in a variable on the page AND in the TempData("YourVariableName") object. Create the Action Link with the Saved URL. When the ajax request is fired it will overwrite the value in Request.URL. So, Check for a value in the TempData("YourVariableName"), if it is there, use that value AND Reset the TempData("YourVariableName") value. This will keep the original value of the page URL even after many ajax requests have been triggered. Code in Visual Basic:
#Code
Dim LastURL As String = ""
If Not TempData("LastURL") Is Nothing Then
LastURL = TempData("LastURL")
TempData("LastURL") = LastURL
Else
LastURL = Request.Url.AbsoluteUri
TempData("LastURL") = LastURL
End If
End Code
And pass the value stored in the LastURL variable as a parameter to your action link.

EmberJS Route to 'single' getting JSONP

I'm having trouble with EmberJS to create a single view to posts based on the ID, but not the ID of the array, I actually have a ID that comes with the json I got from Tumblr API.
So the ID is something like '54930292'.
Next I try to use this ID to do another jsonp to get the post for this id, it works if you open the api and put the id, and actually if you open the single url with the ID on it, works too, the problem is:
When, on the front page for example, I click on a link to go to the single, it returns me nothing and raise a error.
But if you refresh the page you get the content.
Don't know how to fix and appreciate some help :(
I put online the code: http://tkrp.net/tumblr_test/
The error you were getting was because the SingleRoute was being generated as an ArrayController but the json response was not an Array.
App.SingleController = Ember.ObjectController.extend({
});
Further note that the model hook is not fired when using linkTo and other helpers. This because Ember assumes that if you linked to a model, the model is assumed to be as specified, and it directly calls setupController with that model. In your case, you need to still load the individual post. I added the setupController to the route to do this.
App.SingleRoute = Ember.Route.extend({
model: function(params) {
return App.TKRPTumblr.find(params.id);
},
setupController: function(controller, id) {
App.TKRPTumblr.find(id)
.then(function(data) {
controller.set('content', data.response);
});
}
});
I changed the single post template a bit to reflect how the json response. One final change I made was to directly return the $.ajax. Ember understands jQuery promises directly, so you don't need to do any parsing.
Here is the updated jsbin.
I modified: http://jsbin.com/okezum/6/edit
Did this to "fix" the refresh single page error:
setupController: function(controller, id) {
if(typeof id === 'object'){
controller.set('content', id.response);
}else{
App.TKRPTumblr.find(id)
.then(function(data) {
controller.set('content', data.response);
});
}
}
modified the setupController, since I was getting a object when refreshing the page and a number when clicking the linkTo
Dont know if it's the best way to do that :s

Laravel 3 - Passing variables across multiple views

I have two forms on two different views. I would like to post the form input to the second view, and then back to the first form upon posting the second form.
I have set up a test with a route that looks like this :
Route::get('/test1', function() {
return View::make('test1');
});
Route::post('/test2', function() {
$flash = Input::get();
return View::make('test2')->with('flash', $flash);
});
Route::post('/test1', function() {
return View::make('test1')->with('flash', $flash);
});
I am only able to pass $flash once. I'm misunderstanding why I cannot pass it again. I feel like I have to extract it again?
You need to add a form field in /test2 and resubmit the $flash data in order to pass it to /test1 via POST. It's a new request, the app will lose the $flash var otherwise.
A different approach could be to store $flash in a session with Session::put('flash', $flash); and accessing it in the next request.
The best method is to store your data in session. It will be available across multiple request . Using Input::flash() will only be available until the next request. See the Laravel docs for Input::flash() and Session

What ActionResult should you return to update just the ActionLink text?

I'm using MVC4 with Entity Framework and like many people I'm new to MVC and trying to get my head around the design patterns.
I have a partial view that displays a list of sessions followed by actionlinks allowing the authenticated member to book into the sessions.
Note: for clarity, I've chopped out most of the code, if a member is booked into a session, it displays "Booked" instead of the action link.
#using OnlineBookings.Website.Models
#{ DateTime currentDate = DateTime.MinValue.Date; }
<form method="post" action="~/Controllers/BookSessionController.cs">
#foreach (SessionsWithBookingInformation s in Model)
{
<p>#s.StartTime.ToString("t")
#s.Description
#Html.ActionLink(
"Book",
"BookSession",
new { sessionId = s.SessionId }
)
</p>
}
</form>
This then displays as part of a larger view:
The actionlinks pass the guid of the session to be booked through to the following function in my controller, which retrieves the memberId from the cookie and uses Entity Framework to create a booking for that member and session.
public ActionResult BookSession(Guid sessionId)
{
using (var db = new OnlineBookingsEntities())
{
// see if the member id is stored in a cookie
if (Request.Cookies["memberId"] != null)
{
var memberId = new Guid(Request.Cookies["memberId"].Value);
db.Bookings.Add(new Booking
{
BookingId = Guid.NewGuid(),
MemberId = memberId,
SessionId = sessionId,
BookingTime = DateTime.Now
});
db.SaveChanges();
}
}
// this refreshes the entire page
/// is there a better way to just replace the actionlink they clicked on?
return RedirectToAction("Index", "Home");
}
All this is working nicely and bookings are being effectively recorded.
But, I'm trying to figure is if the return from the BookSession function can just update the actionlink text.
Ideally, on success, I want to replace the ActionLink in my partial view with the word "Booked" and on failure I want to replace it with the failure condition like "Session full".
Or I could just update my partial view, because that will do the same thing.
Am I missing something simple here? Or, am I barking up entirely the wrong tree?
Your question is great and really well explained, but it's also a little vague since it's a bit of a "What should I do?" question. Here are a few options that might help you develop a solution.
Redisplay the same view. Return whichever view the user was on for them to submit the link. This will look like a simple refresh.
return View();
Submit the request via AJAX and update via a partial view. Put an id tag on a span or similar HTML element with an individual booking's details inside. Submit the request with AJAX, perhaps via #Ajax.ActionLink, and have your action return a partial view.
return PartialView("_OnlineBookingPartial", model);
Once your partial view is returned, update the specific booking with the data returned.
Use AJAX again, but return JSON. Another way might be that you use AJAX again but instead you return JSON and do something with it. You could, for example, return text in which you would replace Book with; i.e. "Session full" or "Booked!".
return new JsonResult
{
Data = "Booked!"
}
Personally, I'd probably use AJAX to update with a non-AJAX (non-Javascript) fallback.
You can do this by using #Ajax.ActionLink and checking if the request is AJAX or not inside your controller action.
if (Request.IsAjaxRequest) {
return PartialView("_OnlineBookingPartial", model);
}
return View();
This means that if the browser has Javascript enabled and supports AJAX, it will be used and the whole process will be seamless and instant for the user. If Javascript is disabled, the page will simply refresh.

jQuery: execute function on matched elements returned via Ajax

This jQuery selector matches a Rails 3 HTML form for a new model: $('form[id^="new_"]')
I'd like to have a simple focus function run each time a matching form loads. Sometimes the forms are loaded via a simple GET but also via Ajax. In the latter case, the content returned can be either HTML or escaped JS.
I was hoping jQuery would be able to match all cases via the selector, .on(), and the "load" event, but I can't seem to make that work for ANY case. Code:
$(document).ready(function() {
$('form[id^="new_"]').on("load", function(){
console.log("Matched!")
});
})
Any ideas?
Thanks Justice. I'm afraid I wasn't able to get your code to work. I'm using the following callback with the new custom event defined outside it as shown and I don't think the $('form') is triggering the event.
$('.shows-children').bind('ajax:success', function(evnt, data, status, xhr){
var boxSelector = '#' + $(this).data("shows");
$(boxSelector).html(xhr.responseText);
$('form').trigger('customevent');
});
$(document).on('customevent','form[id^="new_"]', function(){
console.log('Matched!')
});
(I'm surprised it seems more involved than expected to have jQuery act on HTML returned in an Ajax response.)
$(document).on("change","form[id^=\"new_\"]" function(){
console.log("Matched!")
});
For delegation, you want to delegate the original selector to a parent, as the event will bubble up.
However, load does NOT bubble up. In this case, change may suffice, but it'll trigger and attempt to see if the delegate is valid every time the document changes.
I would then suggest that you create a custom event after AJAX loads for the form.
Example:
$(document).on("customevent","form[id^="new_"]" function(){
console.log("Matched!")
$.ajax(url, function(response){
//success
$(document).append(response);
$('form').trigger('customevent');
});
});
HTH