Showing success dialog on HTTP Post - asp.net-mvc

I have a requirement that when a user successfully posts some form data, I would like a modal dialog to display whether the POST was successful or not, along with resetting the view to it's empty state (if successful).
How would I go about this?
I have the POST logic working correctly, but as it stands, there is no feedback indicating that the operation was a success or not.

Answer 1:
public ActionResult Index(string message)
{
if(!string.IsNullOrEmpty(message)){
ViewData["successmessage"]=message; //Or you can use Viewbag
}
return View();
}
[HttpPost]
public ActionResult Index()
{
...............
return RedirectToAction("Index",new{ message="Saved successfully" });
}
Just alert ViewData["successmessage"] on View with Javascript alert box.
On View just show alert box as alert('#ViewData["successmessage"]')
Answer 2:
[HttpPost]
public ActionResult Index()
{
...............
TempData["successmessage"] = "Saved successfully";
return RedirectToAction("Index");
}
View(Index.cshtml) :-
#{
var message = TempData["successmessage"] ?? string.Empty;
}
<script type="text/javascript">
var message = '#message';
if(message)
alert(message);
</script>

Firstly, you have to add a listener at the front side, mostly with jquery.ajaxSetup function.
Then you need to let front listener know it is the successful request to display dialog, add a special code or something like that.
C# Code:
return Json(new{Code = 200, Message = "some text"}, JsonRequestBehavior.AllowGet);
Javascript Code:
$.ajaxSetup({
success: function(xhr){
var response = JSON.parse(xhr.responseText);
if(response & response.Code == 200 && response.Message) {
// pop up dialog with message here
}
}
})

Related

ASP.NET MVC 4: Rendering a view from another controller after the original view is rendered failed (using ajax post)

Lets say we have the followings:
Login Action:
public ActionResult Login(string returnUrl)
{
ViewBag.ReturnUrl = returnUrl;
return View();
}
Register Action:
public ActionResult Register()
{
return View();
}
Login View:
<script>
$(function () {
var url = '#Url.Action("Login", "Account")';
$.ajax({
url: url,
type: 'POST',
data: { UserName: "user1", Password: password1 },
success: function () { },
error: function () { }
});
});
</script>
#{
ViewBag.Title = "Login";
}
Register View:
#{
ViewBag.Title = "Register"; }
<h2>Register</h2>
To process the ajax post, this is the login post action
[HttpPost]
public ActionResult Login(string UserName, string Password)
{
if (WebSecurity.Login(UserName, Password) == true)
{
return RedirectToAction("Register");
else
{
this.ControllerContext.HttpContext.Response.StatusCode = 404;
return new EmptyResult();
}
}
Now the issue and the question
Okay, assuming that when the application started it goes to Account/Login, and assuming there exists account for user1, I would expect the Register View will be rendered in the browser (I am using IE 8).
However, what I see, only the Login View is rendered eventhough when I trace the code in debug, the Register View is getting processed. I don't understand why I don't see the Register View?
Is my understanding wrong or is there a bug in asp.net mvc?
What is happening is the ajax call itself is receiving the redirect and sending another request to the new Register URL. Because this is not a request from your browser, but instead the ajax, the response from the Register page is in the success response of the ajax call which your doing nothing with.
See: Returning redirect as response to XHR request
Solution
You can either use a standard form.submit instead of ajax post, or you can return a json response that includes the url to redirect to return Json( new { redirectTo = Url.Action("Register")}); and code your javascript success handler to use that redirectTo property to set window.location to cause the browser to navigate to the new URL.

ValidationMessage and ModelState.AddModelError not working

I want to do cusotm validation and return false and show message in case of validation fail.
In controller below code is used to submit posted data to database.
[HttpPost]
public JsonResult SubmitDa(IList<AdViewModel> s, String section)
{
...........
..........
ModelState.AddModelError("MessageError", "Please enter AttendanceDate");
JSONSubmit r = new JSONSubmit();
r.ErrorCount = iError;
r.errors = errors;
return Json(r, JsonRequestBehavior.AllowGet);
}
Below is the code in view file (cshtml)
#Html.ValidationMessage("MessageError")
.....
$.AJAX call to `SubmitDa` controller's method.
Message is not appearing at "MessageError" validation message. please suggest me what is wrong here.
Thanks
If you want to use the modelstate for errors you shouldn't really be sending a JSON response. Having said that you can handle it by having the controller return JSON only in the case of success, and the page handles the response differently
IE:
[HttpPost]
public ActionResult SubmitDa(IList<AdViewModel> s, String section)
{
...........
..........
ModelState.AddModelError("MessageError", "Please enter AttendanceDate");
JSONSubmit r = new JSONSubmit();
r.ErrorCount = iError;
r.errors = errors;
if (r.ErrorCount != 0)
return Json(r, JsonRequestBehavior.AllowGet);
return View("ViewName", s); // <-- just return the model again to the view,
// complete with modelstate!
}
on the page something like:
<script>
$("#buttonId").click({
$.ajax({
type: "POST",
url: "PostBackURL",
data: $("#formID").serialize(),
success: function (response){
//test for a property in the JSON response
if(response.ErrorCount && response.ErrorCount == 0)
{
//success! do whatever else you want with the response
} else {
//fail - replace the HTML with the returned response HTML.
var newDoc = document.open("text/html", "replace");
newDoc.write(response);
newDoc.close();
}
}
});
});
</script>

View not refreshing after AJAX post

I have a view (Index.cshtml) with a grid (Infragistics JQuery grid) with an imagelink. If a user clicks on this link the following jquery function will be called:
function ConfirmSettingEnddateRemarkToYesterday(remarkID) {
//Some code...
//Call to action.
$.post("Home/SetEnddateRemarkToYesterday", { remarkID: remarkID }, function (result) {
//alert('Succes: ' + remarkID);
//window.location.reload();
//$('#remarksgrid').html(result);
});
}
Commented out you can see an alert for myself and 2 attempts to refresh the view. The location.reload() works, but is basically too much work for the browser. The .html(result) posts the entire index.cshtml + Layout.cshtml double in the remarksgrid div. So that is not correct.
This is the action it calls (SetEnddateRemarkToYesterday):
public ActionResult SetEnddateRemarkToYesterday(int remarkID) {
//Some logic to persist the change to DB.
return RedirectToAction("Index");
}
This is the action it redirects to:
[HttpGet]
public ActionResult Index() {
//Some code to retrieve updated remarks.
//Remarks is pseudo for List<Of Remark>
return View(Remarks);
}
If I don't do window.location.reload after the succesfull AJAX post the view will never reload. I'm new to MVC, but i'm sure there's a better way to do this. I'm not understanding something fundamental here. Perhaps a nudge in the right direction? Thank you in advance.
As you requesting AJAX call, you should redirect using its response
Modify your controller to return JSONResult with landing url:
public ActionResult SetEnddateRemarkToYesterday(int remarkID) {
//Some logic to persist the change to DB.
var redirectUrl = new UrlHelper(Request.RequestContext).Action("Index", "Controller");
return Json(new { Url = redirectUrl });
}
JS Call:
$.post("Home/SetEnddateRemarkToYesterday", { remarkID: remarkID }, function (result) {
window.location.href = result.Url
});
After Ajax post you need to call to specific Url..
like this..
window.location.href = Url
When using jQuery.post the new page is returned via the .done method
jQuery
jQuery.post("Controller/Action", { d1: "test", d2: "test" })
.done(function (data) {
jQuery('#reload').html(data);
});
HTML
<body id="reload">
For me this works. First, I created id="reload" in my form and then using the solution provided by Colin and using Ajax sent data to controller and refreshed my form.
That looks my controller:
[Authorize(Roles = "User")]
[HttpGet]
public IActionResult Action()
{
var model = _service.Get()...;
return View(model);
}
[Authorize(Roles = "User")]
[HttpPost]
public IActionResult Action(object someData)
{
var model = _service.Get()...;
return View(model);
}
View:
<form id="reload" asp-action="Action" asp-controller="Controller" method="post">
.
.
.
</form>
Javascript function and inside this function I added this block:
$.ajax({
url: "/Controller/Action",
type: 'POST',
data: {
__RequestVerificationToken: token, // if you are using identity User
someData: someData
},
success: function (data) {
console.log("Success")
console.log(data);
var parser = new DOMParser();
var htmlDoc = parser.parseFromString(data, 'text/html'); // parse result (type string format HTML)
console.log(htmlDoc);
var form = htmlDoc.getElementById('reload'); // get my form to refresh
console.log(form);
jQuery('#reload').html(form); // refresh form
},
error: function (error) {
console.log("error is " + error);
}
});

How to return back a message after a submit

I have the following code which is not working as expected. I want to have a retrun from the controller and using alert display the value returned from the controller.
$('#change').dialog({
autoOpen: false,
width: 380,
buttons: {
"Close": function() {
$(this).dialog("close");
},
"Accept": function() {
var test = $("#ChangePasswordForm").submit();
alert(test);
}
}
});
In my controller I want to return a string
[AcceptVerbs(HttpVerbs.Post)]
public string ChangePassword(string Name)
{
var msg = "Cool!";
if (name != null)
return msg;
}
How can I do that?
Your controller needs to return a type that derives from an ActionResult.
If you want to display a simple confirmation message you can add it to the ViewData bag like this:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult ChangePassword(string name)
{
if (!string.IsNullOrEmpty(name))
{
ViewData["msg"] = "Cool";
}
return View();
}
Then, in your view, check for the presence of the value, and display it if it's there:
<% if(ViewData["msg"] != null) { %>
<script type="text/javascript">alert('<%= ViewData["msg"].ToString() %>')</script>
<%} %>
First of all, im assuming you are using an ajax form for this. I also assume you have a or something for putting your text into. All you have to do is set the UpdateTargetId to point at the id of the element you want to update with the text
<%using (Ajax.Form("ChangePasswordForm", new AjaxOptions { UpdateTargetId = "result" })) %>
.
[HttpPost]
public ContentResult ChangePassword(string s)
{
var msg = "Cool!";
if ( s != null ? return Content(msg, "text/plain") : return Content("An error has occured", "text/plain") );
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult ChangePassword(string Name)
{
var msg = "Cool!";
if (name != null)
{
return Content(msg, "text/plain");
}
else
{
return Content("Error...", "text/plain");
}
}
Don't submit the form as that will perform a postback and cause the dialog to be removed.
Instead perform an AJAX post to the Controller Action and return a JsonResult containing the data.
Hook into the success callback from the Ajax request, and call alert passing the data from the Json object.
You'll probably wan't to use a loading mask after clicking submit so the user knows something is going on.

asp.net mvc custom exception filter to force a return of full view, not partial

I have a custom exception filter that I'm calling by virtue of adding a [CustomExceptionFilter] attribute to my class. It works as I'd like it to, however if the action method is returning a partial view (through an ajax request), the exception (which is basically a redirect to a not authorized page), is loading up the partial view with that page. Is there a way I can force it to reload the 'parent' url?
Here is the code for the custom exception filter
public class CustomExceptionFilter : FilterAttribute, IExceptionFilter
{
public void OnException(ExceptionContext filterContext)
{
if (filterContext.Exception.GetType() == typeof(CustomSecurityException))
{
filterContext.ExceptionHandled = true;
RequestContext rc = new RequestContext(filterContext.HttpContext, filterContext.RouteData);
string url = RouteTable.Routes.GetVirtualPath(rc, new RouteValueDictionary(new { Controller = "NoAccess", action = "Index", message = filterContext.Exception.Message })).VirtualPath;
filterContext.HttpContext.Response.Redirect(url, true);
}
}
}
This is something you need to handle on the browser. Try handling the error() on jQuery.ajax() call for example (and obviously don't return redirect..).
I would suggest letting the exception bubble up to the client and handle it like Maxwell suggested.
In our previous project we used a specific actionfilter for handling ajax errors (borrowed from Suteki Shop). Note that the response status is 500 (internal server error). An error status is required for the response in order to call de Error() delegate within a JQuery.ajax() call.
public class HandleErrorWithAjaxAttribute : HandleErrorAttribute
{
public HandleErrorWithAjaxAttribute()
{
ShowStackTraceIfNotDebug = true;
}
public bool ShowStackTraceIfNotDebug { get; set; }
public override void OnException(ExceptionContext filterContext)
{
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
string content = ShowStackTraceIfNotDebug ||
filterContext.HttpContext.IsDebuggingEnabled
?
filterContext.Exception.StackTrace
:
string.Empty;
filterContext.Result = new ContentResult
{
ContentType = MediaTypeNames.Text.Plain,
Content = content
};
filterContext.HttpContext.Response.Status =
"500 " + filterContext.Exception.Message
.Replace("\r", " ")
.Replace("\n", " ");
filterContext.ExceptionHandled = true;
filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
}
else
{
base.OnException(filterContext);
}
}
}
I use the OnFailure hanlder in form tag.
<form id="AJAXForm" method="post" action=""
onsubmit="Sys.Mvc.AsyncForm.handleSubmit(this, new Sys.UI.DomEvent(event),
{ insertionMode: Sys.Mvc.InsertionMode.replace, httpMethod: 'POST',
updateTargetId: 'myPartialPage', onSuccess: Function.createDelegate(this, ajaxFormSucced),
onFailure: Function.createDelegate(this, ajaxFormFailure) });" >
...
function ajaxFormSucced(){
// Code for success
}
function ajaxFormFailure(){
// Code for failure
}
You can verify if the request is an ajax request or not.
You could for example do the following...
if (!filterContext.HttpContext.Request.IsAjaxRequest()){
//Return a ViewResult
//filterContext.ExceptionHandled = true;
//filterContext.Result = new ViewResult { ViewName = "Error" ... };
}
else{
//An ajax request.
//return a partial view
}
However, as Maxwell said you could let the exeption bubble up if it is an ajax request and handle the error on the client. You can setup globally a way of handling exceptions in ajax requests like it is described here
Did you try clearing the response? The controller may still be setting response content.
filterContext.HttpContext.Response.Clear()
filterContext.Result = new JsonResult { Data = new { Message = message } };
filterContext.HttpContext.Response.StatusCode = 500;
filterContext.ExceptionHandled = true;
filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
This link helped me
Handling ASP.NET MVC exceptions when posting to the controller via Ajax using jQuery
Lastly, When testing the javascript function, start with alert on the first line. Any javascript errors in your function are likely to stop the function in mid execution without javascript error feedback via the browser (depending on your setup).
This will help you.
Just add .IsAjaxRequest extension method and return 403 status code to browser, jquery ajaxError will handle it redirecting to login page
As Maxwell says, handle on the client, using something like this
function handleError(ajaxContext) {
// Load parent
}
#using (Ajax.BeginForm("Index", "Home", new AjaxOptions
{
UpdateTargetId = "MyDiv",
OnFailure = "handleError"
}))
What you must do though is make sure in the controller ActionResult code for NoAccess contains the following code, so that your ajax error is triggered.
HttpContext.Response.StatusCode = 401;

Resources