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).
Related
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
}
});
});
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.
I'm new to Asp MVC, and I'm trying to accomplish a little async update (I'm using MVC3 RC2, with Razor, but I can manage with ASPX solutions too).
I have a Master page, which renders a shopping cart box on every page by calling Html.RenderAction("Cart","Shop"). The Cart action of the ShopController calls the database, etc, and outputs the results. This works.
First problem: if I put an ActionLink in this partial view (like Html.ActionLink("Remove")), then even if I call PartialView() from the Remove action, it renders only the shopping cart, and nothing else (in essence, my page disappears).
Second problem: There is a div called "cartContent" inside this partial view. I want to be able to put a link ANYWHERE (not just on the Master page or in the partial view), which when pressed calls a controller Action, and then updates ONLY the cartContent div based on the results. I've tried Ajax.ActionLink but it does the same as Html.ActionLink, even though I imported the Microsoft.MvcAjax js libs.
Also, if I solve the first problem, I want that to be async as well.
What solution do I use? I've tried setting UpdateTargetID to "cartContent", I've tried wrapping the cartContent into an Ajax.BeginForm, nothing. Do I HAVE to use jQuery (which I know nothing of)? Do I serialize some response to JSON, and update the div manually in Javascript? (I'm not really good at JS, I'm coming from the C# side of things)
You put a link wherever you want:
#Html.ActionLink("remove item", "remove", "somecontroller",
new { id = Model.Id }, new { #class = "remove" })
And then in a separate javascript file:
$(function() {
$('.remove').click(function() {
// when the link is clicked
// perform an ajax request:
$.ajax({
url: this.href,
type: 'delete',
success: function(result) {
// when the AJAX call succeed do something with the result
// for example if the controller action returned a partial
// then you could show this partial in some div
$('#someDivId').html(result);
}
});
// don't forget to cancel the default action by returning false
return false;
});
});
Remark: if the div you are updating contains also the link then you might need to use the .live() function or the click event handler will not work the second time because the DOM will be modified:
$('.remove').live('click', function() {
...
});
I have a dropdown list on my master page that needs to postback after being changed. After the postback, whatever page initiated the postback needs to be re-displayed.
My question is where do I handle this? Obviously I do not want to have to modify every Action in my project... My guess is to maybe postback to some other fixed action and have that action redirect back to the page that is the referrer. Am I correct? Any thoughts?
Thanks.
Jason
In Site.Master, I ended up wrapping the dropdown within its own form that posted back to a dedicated controller/action.
<% Using Html.BeginForm("ChangeRole", "Home")%>
<div id="roleSelector">Change Role: <%=Html.DropDownList("Role", DirectCast(ViewData.Item("Roles"), SelectList), New With {.onchange = "this.form.submit();"})%></div>
<% End Using%>
In the controller I used the following code to change the mode and then redirected back to the referring URL.
<AcceptVerbs(HttpVerbs.Post)> _
Public Function ChangeRole() As ActionResult
Me.CurrentUser.SetRole(DirectCast([Enum].Parse(GetType(Models.ApplicationRoles), Me.Request.Item("Role")), Models.ApplicationRoles))
Return Redirect(Request.UrlReferrer.ToString())
End Function
I am unsure if this is the recommended way but I have been unable to think of another solution.
When you post back from the dropdown list change what are you doing? Can you maybe handle this in a jQuery call thus eliminating the need to re-display the page at all?
Calls to Action Methods can be asynchronous as griegs says, as such, you can post whatever information you need from the radio buttons to an action method without needing to reload the page.
If you need to update a part of the page, you can replace it with the contents of a rendered action method. If you use the jQuery ajax methods, you can post specific information to your methods.
For example, something like this:
$(document).ready(function()
{
$("#myRadioButton").change(function()
{
//Post to your action method, with the value of the radio button, function to call on success
$.post('yourActionMethodUrl', $(this).val(), function()
{
//Update some part of the page
});
});
});
This is based on memory, so you may need to check the syntax.
At this moment I am calling my index view in one of two ways. Using the normal http view and serializing it JSON. In order to test it I am using the code below, and it works. I want to get it with a http get call. Like (http://localhost/article,json or something similar. Any ideas.
$.getJSON("/Article", function(json) {
$.each(json, function(i, article) {
alert(article.title);
});
});
At this moment the index called to /article is being differentiated with the following IsAjaxRequest method. but my real question is if I am able to get around the .getJSON method in JQuery to test the following code.
if (Request.IsAjaxRequest()) {
return Json(articles);
} else {
return View(articles);
}
If you are trying to reuse the same action method for both a full GET (the page load) and an AJAX call (via getJSON), you'll run into issues because each action method should have a unique name. Otherwise, the MVC engine can't tell which action method should be called when a particular Url is requested.
You'll need two separate actions: one for the full page load that returns a ViewResult and the other for the AJAX call that returns a JsonResult. If you need the Urls for these actions to look the same, you can also play around with mapped routes that direct to different action methods.
So, how about:
/Article/Index
Maps to the default Index action (full page load)
/Article/Refresh
Maps to the Refresh action (asynchronous JSON call)
I'm not sure I understand the question correctly, but can't you make an optional parameter called "format", so that you pass in ?format=json to switch what reply type you get back?
if(Request.IsAjaxRequest() || (!string.IsNullOrEmpty(format) && format.Equals("json"))
{
...
}
If you're wondering how to test your action and you're talking about doing automated testing, see if this post answers your question.