View Master Page and PostBack - asp.net-mvc

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.

Related

What would be the correct return type in MVC when no page refresh required

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
}
});
});

MVC controls not working properly without page refresh

I've got an MVC controller that can be called via form submission in a couple different places. The controller then renders a view whose primary purpose is to allow the user to send the document or post it to an external site, as well as fill in text fields that will be used in the notification email.
I am performing validation on these fields - the user can enter custom subject/body text. If they do not, they will receive a popup alert and can either return to the form or submit it using default text indicated in the placeholder value.
The problem is that when the user first reaches this page and clicks the send button, no input in the textboxes is actually registering and it gives the empty string notification regardless of what is actually in the fields; however, if I hit F5 and try again, the input works perfectly.
I feel like this has something to do with the form submissions that initially call this controller being done via POST action, whereas it seems to work fine with the GET on page refresh. I just can't figure out how to either get the content to respond properly when the controller is called via POST, or how to submit the form without posting the data.
Thanks in advance for reading and any help.
Here is the calling controller:
public ActionResult Index(FormCollection collection)
{
//modelbuilding code
return View (Model);
}
The code that calls the controller always uses this format: (in this case, it would be called from the Recipients/Index view.
#using(Html.BeginForm("Index", "Distribution", FormMethod.Post )) {
//form values
<input type="submit" data-role="button" value="Done"/>
}
Here is the relevant part of the view and the JS validation function:
<div id="SubjectTemplate">
<p>Subject: <input id="emailSubjectTextBox" name="EmailSubject" placeholder="#EmailSubject" /></p>
</div>
Send Notification
<script>
function validateInput() {
var possibleErrors = [];
if (!(document.getElementById('emailSubjectTextBox').value)) {
possibleErrors.push('#incompleteEmailSubject' + '\n');
}
//more validation that works the same way and has the same problem
if (possibleErrors.length > 0) {
if (confirm(possibleErrors))
{
window.location.href = '#Url.Action("Send")'
}
}
else {
window.location.href = '#Url.Action("Send")'
}
}
</script>
I'm not sure I fully understand your question, but generally speaking you should not use the same action for POST and GET.
Even more importantly, you should not be using POST if your action does not have some kind of side effect. If all you are doing with your form submission is making some kind of choice then you should be using GET.
See the following post for more information and examples of how to perform ajax GET requests using jQuery: http://www.jquery4u.com/ajax/key-differences-post/
Regardless of what you are trying to do, it is very good practice that POST calls perform some action, and then redirect to a GET action which returns to the user.
[HttpPost]
public ActionResult Index(FormCollection collection)
{
//do whatever you need to save the record
return RedirectToAction("Index")
}
[HttpGet]
public ActionResult Index()
{
//modelbuilding code
return View (Model);
}
Not only does this help your controller adhere to a RESTful methodology, it also stops the user getting that annoying 'Are you sure you want to resubmit this page' if they happen to press f5
Hope this helps.
I found the problem resulted from jQueryMobile automatically utilizing AJAX to post forms. I solved this by including new {data_ajax = "false"} to the Html.BeginForm statements.

How to implement a form button which doesn't change the page

I have a view with the following code:
#using (Html.BeginForm("GenerateQrCode", "QrCodeGenerator", FormMethod.Post ))
{
<input type="submit" value="Generate" />
}
It's just a submit button, which calls the code in my controller:
public void GenerateQrCode()
{
}
Is it possible for a method in my controller to return a value from the form, but without going to a different page? Because I notice that currently, on pressing the form button it tries to navigate to a non-existing 'GenerateQrCode' page (the same name as the controller method).
UPDATE:
Something I've tried is making the controller method return an ActionResult, and return a 'RedirectToAction', and simply calling the same view. However, I also had code in this method 'ViewBag.Message = "myMessage"; and then in my view I had the code '#ViewBag.Message', so I hoped that the view would update with the ViewBag message property, but it doesn't appear so.
The version of Html.BeginForm you're using tells the submit button to post to the GenerateQrCode action. Perhaps you could try another overload of Html.BeginForm that better suits your purposes?
Using javascript:
Handle the click event.
In the handler, prevent the default action and stop the event propagation.
Make and AJAX call to the server with the form data.
Get the response and take further actions.
So if I have this right, you want to submit an action without actually taking into account the response from the server. Sounds like you need jQuery post:
$.post(url, $("form selector").serialize(), function () {
// This is where you put a callback function.
});
That is all you need. This will post the data. What you can do is call this from a button click event instead of a form submit button. Or, you can override the submit event on the form and put this as your first line of code:
e.preventDefault();
where e is your event arguments. This will prevent the default action from occurring, which in this case is the submission of the form and the loading of the response.
The simplest method of doing this was simply to use the RedirectToAction method, specifying the name of the controller in the parameters. I also used the TempData variable to pass the results (in this case just a string value) back to the view, and into a ViewBag variable.
public ActionResult QrCodeGenerator()
{
ViewBag.Message = TempData["Message"];
return View();
}
public ActionResult GenerateQrCode()
{
TempData["Message"] = "myMessage";
return RedirectToAction("QrCodeGenerator");
}

ASP MVC + AJAX, trying to Update a div asynchronously

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() {
...
});

How can I use Html.ValidationSummary with Ajax.BeginForm?

I have an AJAX form that I am creating in my MVC project. If the form is submitted using normal browser function and a page refresh occurs I get validation information rendered in the form (the built in MVC validation based on ViewData.ModelState).
Is there a similiar validation mechanism for AJAX forms?
<% using (Ajax.BeginForm("Create", "GraphAdministration", new AjaxOptions()
{
OnSuccess = "newGraphSuccess",
OnFailure = "newGraphFailure",
HttpMethod = "POST"
}))
{ %>
<!-- some form stuff in here !-->
<% } //end form %>
It really depends on where you are getting the content from to display once the form has been posted. The Validation summary is performed created on the server so that is where you have to do the work.
As an example I was using some partial content in an .ascx file to render a form. You get the form in the page the first time round by calling the action directly with Html.RenderAction
You would have your Ajax.BeginForm etc. in the .ascx file. Then call it directly in an action.
When the Ajax call is made from the browser you get it to post to the same action. That way you can do all of the server side validation that you would normally. You should set up the Ajax call to replace the original form with the new html that is returned by the action.
One thing that you have to be aware of is that the replace JavaScript will replace the content of an element not the element itself so remember to us the id of a surrounding element.
Apologies if that is a little convoluted, if you want more details just comment and I'll flesh out the relevant bits.
Extra Detail:
All of this assumes that you are doing all of the validation on the server.
You are going to have a View that has all of the page stuff in it and then some partial content in a .ascx file, this is where your ajax form lives, it needs to be set to replace content by id. Its easiest if it has the same name as the action your ajax is going to call.
You can use Html.RenderAction to get it into the View. You can also pass in data with other versions of the same method. Your essentially calling it in the same way your ajax code will.
You will need to wrap it all in a div with an id set. Use this id in the partial as the content to replace.
When you render the page the html for the form and all of the ajax stuff will get put in.
When the ajax action is called the partial content will be returned with any validation performed. It will replace the content of the div that you gave the id to.
You can have different versions of the action by using [AcceptVerbs(HttpVerbs.Get)] and [AcceptVerbs(HttpVerbs.Post)] attributes
The main problem with this method is that its not self contained, the div with the id is external to the partial.

Resources