How would you use jQuery to post to a different controller using Razor syntax? Below is the code I'm attempting to use. Each of the alerts pop up the exact information I am expecting except for the one containing the #Url.Action. This gives me a URL that just contains the Controller and method (i.e. /Agent/Details). The sNumber is completely missing.
Oddly enough, this code is still posting to the controller properly, with the correct sNumber parameter. However, once the controller goes through the process of grabbing the agent from the database and attempting to render the view, nothing happens. The user stays on the same page.
Here is the jQuery
alert("input: " + item + ", map: " + map[item].sNumber);
var sNumber = map[item].sNumber;
alert("variable: " + sNumber);
alert('#Url.Action("Details","Agent")', { id: sNumber });
$.post('#Url.Action("Details","Agent")', { id: sNumber });
There is a ton of code in controller, so I'll spare you by not posting it. However, this is the final line
return View(bigAgent);
The controller uses the sNumber input parameter to grab the record from our database and pass that agent's info to the Details view. I've checked the contents of the bigAgent object using both the jQuery search and our regular search (which redirects properly), and they are one and the same. For whatever reason, you are just not directed to the Details page when using the jQuery search.
It's not odd that it's posting correctly. You are using a POST request afterall, so the sNumber parameter doesn't belong in the URL as it would with a GET request (e.g. /Agent/Details/3).
You're not being redirected because when you use jQuery AJAX methods, they happen asynchronously. You need to handle the redirect yourself in the success callback of the $.post() function.
$.post('url', { data }, function(data) {
// callback
});
It sort of seems like you shouldn't be using AJAX at all and should be performing a regular form submission so you can handle the redirect in your controller.
Related
I have an ASP.NET MVC 4 application that has one section that behaves like a SPA. It's a page with multiple steps and, because I'm working sessionless, I'm sending from the client to the server (using AJAX) the ID of the entity in every request (I'm also sending a GUID that needs to correspond to the ID in order to be valid, this is for detecting data tampering). Let's say that the user is on step 3 and one of the following things happen:
1) An error occurs: I have a global filter that inherits from HandleErrorAttribute that logs the error and sends an email, and after all, it shows a custom error page. The problem is that if the user press the browser's back button, the hidden fields are lost and the process has to start from step 1 again.
2) The user navigates away from the page. I think that I can warn the user with a dialog.
Thanks in advance.
EDIT:
I'm showing a warning dialog when the user wants to navigate away.
$(window).bind('beforeunload', function () {
if ($("#id").val() != "") {
return 'If you leave the page, the offer will be lost.';
}
});
If after he navigates away presses the browser's back button, I'm redirecting him to the first step of the flow because the previous entered data is lost.
if ($("#id").val() == "" && window.location.hash != "") {
window.location.hash = "";
}
It sounds like your AJAX request for the next step is hitting a Controller action that's redirecting you to a new page. That's fine, and it's good you're keeping your server code stateless by sending up all the relevant information back up to the Controller for each step. However, doing it this way means that you're stuck using the custom error page, and you're going to have trouble making that work well with your setup.
My suggestion: move more towards a true SPA. When I visit Step1, the Controller should send back a whole page (like you're doing). Let's assume that this page has a container like <div id="step-container"> ... HTML for each step is in here ... </div>.
Now, when you click the button to move on to step 2, instead of hitting the controller action expecting to get redirected to a new page, send out an AJAX request for a Partial View with the Step 2 content.
On the server, change your Step2.cshtml from a regular view to a Partial View (you can make a new View and click the Partial View checkbox), and for convention's sake, you should probably rename it _Step2.cshtml. In your Controller action public ActionResult Step2(... data), you could change your return statement to return PartialView("_Step2"), but leaving it as return View("_Step2") is just fine.
Now for the important part, the client. Here, you're issuing an AJAX request for that Partial View.
// Set the data from your form in this variable
var data = { };
// Issue a GET request out to the controller action. Make sure the URL is right
$.get('/Steps/Step2', data)
.done(function(result) {
// This promise will execute when we get the content of the Partial View back from the server
// The result variable should have the HTML for the view
// Use jQuery to set the content in your step div to the new HTML
$('#step-container').html(result);
})
.fail(function(error) {
// This promise function will execute if there is an error in the Controller
// and it returns something other than a 200 type response code
// Handle the error here, maybe showing a dialog or trying to fix the error
alert('Sorry, form submission failed');
});
My web page uses Jquery to overload a screen. In this overlay, the user can type some detail and click the submit button.
What I'd like to do is, when the user clicks on submit, the overlay doesn't disappear (as it would do with a page refresh), but a message appears, such as "all done"
The question I have though, is, what is the correct return type? I've gotten myself into a muddle I'm sure.
I tried to make the return type string, and return the string. Sadly, this redirected me to a page with the string value.
I then thought I would need to return a ContentResult() with return Content(myString). The result was the same as returning a string.
I then tried to return void, and simply in my controller use ViewBag.Status ="All done"; This now takes me an empty page.
How can I make the message show "All done" or "Complete" without losing the state? Am I trying to do the impossible without Ajax or similar?
Yes, you are trying to do the impossible. When a controller action gets hit on a synchronous request (e.g. a form submission) you are always going to get a full-page load. That's exactly what a synchronous request is. In effect, the "refresh" has already happened before your action code even runs; the return type of the action is irrelevant. For partial updates, you need an asynchronous request, which means AJAX.
The typical approach to this would be to load in your overlay and then, submit the form from the overlay via AJAX, return a partial view and target a container with jQuery. You'd typically create some kind of generic wrapper for your overlays that will do this for all form posts within any overlay.
Alternatively, you could look at returning JSON and using a JavaScript templating engine like Handlebars to populate the view.
Either way it's a good idea to look at wrapping all of this up in some "generic" JavaScript code that will do the same thing for form posts in all of your overlays; then you can stop worrying about the client-side code and focus on just returning the right thing from your controller actions.
If you want to do that WITHOUT ajax, you will need to return the whole underlaying page again, including the popup in a visible state.
What you (probably) SHOULD do is to use ajax and return a json result. Something like this jQuery solution:
$(document).on('click', '[type="submit"]', function(){
var $form = $(this).closest('form');
$.ajax({
url: $form.action,
type: 'post',
data: $form.serialize(),
success: function(response){
// write success message to user
}
});
});
lets say I want to a partial view like the following sample
#Html.RenderAction("ListDocuments", "MultiFileAttachments", new { id = jsparameter });
in the jsparameter I want to pass as a parameter that is the result of a javascript function. Maybe this is not logical because javascript runs on the client, but how can I achieve a similar functionality ? thank you in advance
If you need to call a part of a page based on some actions or values determined by actions on the client side, then you should think to use JavaScript (preferably jQuery) and Ajax.
Through jQuery-Ajax, you could easily call a Partial view through the Contoler and since it's a regular HTTP request, you would be able to pass all the parameters you need.
Using code as :
#Html.RenderAction("ListDocuments", "MultiFileAttachments", new { id = jsparameter });
is not possible since it is rendered by the server before it's sent to the client browser.
In the file FirstView.cshtml I have an event - clicking to a cell of a table redirects you to a method:
$.get('#Url.Action("MyMethod", "MyController")', { someParameters });
In the method MyMethod, which is void, I call and event DownloadStringCompleted in which I have:
Response.Redirect(Url.Action("Second", "MyController"));
Second is an action method which returns SecondView. SecondView is my desired view but it never shows on the browser. The breakpoint enters in it, passes it and I get FirstView in the browser.
What could be the reason? Can it be because they are in the same controller?
The methods are like this:
Second return View. In its body, I pass some ViewData parameters.
The event:
I read some JSON data and call the redirection.
The strange thing is that the breakpoint moves through the correct view, but I get the wrong one in my browser.
Srcee,
I believe this is due to the fact that your ajax function is 'done' once it has hit the MyMethod action. The redirect doesn't get fired as it's not part of the pipeline due to the ajax call (at least, this is my basic understanding). An alternative for you would be to do something along the following lines:
$.ajax({
url: '#Url.Action("MyMethod", "MyController")',
data: { id: 123 }, // i.e. someParameters
context: document.body,
success: function(){
window.location = '#Url.Action("Second", "MyController")';
}
});
this is all top of the head stuff and may not work, but is an alternative approach.
[edit] - based on your later edit, i would actually suggest that you don't use ajax at all as it's impossible (as per my comments below) to redirect on the server via an ajax call. see:
asp.net mvc ajax post - redirecttoaction not working
and also:
How can I RedirectToAction within $.ajax callback?
for confirmation on this.
Try not calling Response.Redirect(...) in MyMethod. Instead, call:
public ActionResult MyMethod()
{
return Redirect(Url.Action("Second"));
}
Note that if the controller name is the same as the one you are in, you don't need to explicitly include it.
I just did a test on my dev box, and this works (assuming I correctly modeled your problem).
Basically what I have is web services returning data in xml format. Once I do a call to a webservice to retrive data from web service function (GetUserList) i want to take that data and then dymaically display (no postback) the resulting information. I know several ways of doing this:
webservice sends data back to javascript, javascript then parses, replaces strings or text inside a div or child, or take the information retrieved and then put it into html table format through javascript.
Those are some of the idea's i've came up with, does anyone know the best practice to do this?
Using ASP.MVC (.Net)
It depends entirely on your application. I've both had the action return pure data (usually JSON, not XML) and handled the display in the client and had the action return a partial view. For most complex display scenarios, I think the partial view route is easiest. Essentially, you are returning just the portion of the page (HTML) that is going to be updated. You use javascript in the AJAX callback handler to replace the appropriate element(s) on the page with the HTML you get back from the server. Note that you need to be careful with event handler binding when you do this -- it's almost always the right thing to do to use live handlers in jQuery 1.4+ and rebind all but click handlers in jQuery 1.3.
Example: Assumes that you are calling an MVC action method that returns a partial view. This will call the show action on the foo controller every 5 seconds and update the containerToUpdate (presumably a DIV), with the html returned.
setInterval(
function() {
$.get( '<%= Url.Action( "show", "foo", new { id = Model.ID } ) %>',
function(html) {
$('#containerToUpdate').html( html );
});
}, 5000
);
Server side:
[AcceptVerbs( HttpVerbs.Get )]
public ActionResult Show( int id )
{
var model = ...
if (this.Request.IsAjaxRequest())
{
return PartialView( model );
}
else
{
return View( model );
}
}
The full view (for non-AJAX) may not be necessary -- you may want to just display an error if the user shouldn't be accessing this except through AJAX. If you do support both, just render the partial inside the full view where it's needed so that you reuse the partial view code.