How to display alert message box in asp.net core mvc controller? - asp.net-core-mvc

I want to display alert message box when the account model is invalid.
How should i gonna do this in controller in Asp.Net Core MVC?
Here is my Controller's code
[HttpPost]
public IActionResult Index(Account model)
{
if (model.ID != null && model.PassWord != null)
{
using (var db = new AccountDBContext())
{
var account = db.Account.FirstOrDefault(
a => a.ID.Equals(model.ID) && a.PassWord.Equals(model.PassWord)
);
if(account != null)
return RedirectToAction("Index", "Main");
}
//I want to display error msg box...here like "Check ID or PW".
ModelState.AddModelError("", "Error");
}
return View();
}
I searched the way but there is no "Page" identifier or "Response.write()" Method in this controller class....
How should i gonna do?
p.s
The way that i checked model's validation like that is right way?
(I used a model and check it's partial properties, instead using view model )

Define the error in your controller:
ModelState.AddModelError("Error", "Check ID");
And then display it in the view:
#if (!ViewData.ModelState.IsValid && ViewData.ModelState["Error"].Errors.Count > 0)
{
<div class="alert alert-
<strong>Error!</strong> danger">#ViewData.ModelState["Error"].Errors.First().ErrorMessage
</div>
}
EDIT
To show an alert box, add some javascript in your view, the following uses jquery:
<head>
<script type="text/javascript">
#if (!ViewData.ModelState.IsValid && ViewData.ModelState["Error"].Errors.Count > 0)
{
<text>
$(document).ready(function() {
alert('#ViewData.ModelState["Error"].Errors.First().ErrorMessage');
});
</text>
}
</script>
</head>

Related

MVC 4 Ajax.BeginForm and ModelState.AddModelError

I'm trying to get errors to show up after an ajax submit has returned an error. I'm not sure what I'm missing, but I can't get it to work. This question is basically the same thing - ModelState.AddModelError is not being displayed inside my view but I'm still not having any luck. My experience with Ajax and MVC (any version) is still a bit limited. Here is a very simple example, most of which I took from the previous link.
View: test.cshtml
#model TestProject.VisitLabResult
#Scripts.Render("~/Scripts/jquery.unobtrusive-ajax.min.js")
#Scripts.Render("~/Scripts/ckeditor/ckeditor.js")
#{
AjaxOptions ajaxOpts = new AjaxOptions
{
Url = Url.Action("test"),
HttpMethod = "Post",
LoadingElementId = "loading",
LoadingElementDuration = 500,
OnSuccess = "processData"
};
}
#Html.ValidationMessage("CustomError")
<div id="loading" class="load" style="display:none">
<p>Saving...</p>
</div>
<table>
#for (int item = 0; item < 10; item++)
{
<tr id = #item>
#using (Ajax.BeginForm(ajaxOpts))
{
#Html.ValidationSummary(true)
#Html.AntiForgeryToken()
<td>
<input type="submit" value="Create" />
</td>
<td id = #(item.ToString() + "td")>
</td>
}
</tr>
}
</table>
Controller: HomeController.cs
public ActionResult test()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult test(VisitLabResult vlr, int visitid = 28)
{
try
{
if (ModelState.IsValid)
{
if (Request.IsAjaxRequest())
{
throw new Exception("error");
}
else
return View(vlr);
}
else
return View(vlr);
}
catch (Exception ex)
{
ModelState.AddModelError("CustomError", "The Same test Type might have been already created, go back to the Visit page to see the available Lab Tests");
return View(vlr);
}
}
Model
public class VisitLabResult
{
public int visitid { get; set; }
}
If it is an Ajax request I throw an error and it's caught and an error is added to ModelState. That error never shows up on the page though. Am I approaching this the right way at all? Or do I need to take a different route? I appreciate any help.
Just to clarify the solution for other people hitting this question. The ajax helper fires OnSuccess vs OnFailure based on the returned HTTP Code per the AjaxOptions docs:
OnSuccess: This function is called if the response status is in the 200 range.
OnFailure: This function is called if the response status is not in the 200 range.
In other words, you have to manually specify that there was a failure when returning your ActionResult by changing the Response.StatusCode and then returning whatever values you're expecting in your OnFailure js method. You can drive that based on any business logic you want (i.e. catch Exception ex) or !ModelState.IsValid ...)
[HttpPost]
public ActionResult Search(Person model)
{
if (ModelState.IsValid) {
// if valid, return a HTML view inserted by AJAX helper
var results = PersonRepository.Get(model)
return PartialView("Resulsts", vm);
} else {
// if invalid, return a JSON object and handle with OnFailure method
Response.StatusCode = (int)HttpStatusCode.BadRequest;
return Json(new { errors = ModelState.Values.SelectMany(v => v.Errors) });
}
}
Further Reading:
MVC 4 Ajax.BeginForm and ModelState.AddModelError
ASP.NET MVC “Ajax.BeginForm” executes OnSuccess even though model is not valid

MVC Knockout validation display and

I am using knockout for the first time and I am struggling to get my head around a problem.
I have a page with multiple sections and want to be able to edit a section and submit to the controller, then display the saved details.
Each section is a partial view which contains the display information and the form. They are shown and hidden as required. I have the code working for submitting, but the problem is when the ModelState is not valid. I need to return to the form with the validation message displayed
How can I display the form again when the server validation fails? When the validation fails it currently goes back to the display section.
Also I have noticed the validation message does not display.
I am sure this must be a common problem with a simple fix. I know there are knockout validation tools, but will need to do more complex business logic validation later on and need to get the technique working.
ViewModel:
[Required]
public DateTime? InterviewDate { get; set; }
View:
<div data-bind="if: showAdminInterviewDisplay" id="Display">
<div>
<button data-bind="click: showInterviewForm" id="EditButton">Edit</button>
</div>
<div>
#Html.Label("Inteview Date") :
<label data-bind="text: interviewDate"></label>
</div>
</div>
<div data-bind="if: showAdminInterviewForm" id="Form">
<div>
#Html.Label("Interview Date")
<input data-bind="value: interviewDate" id="interviewDatePicker" />
#Html.ValidationMessageFor(m => m.InterviewDate)
</div>
<div>
<button data-bind="click: saveInterviewDate">Submit</button>
</div>
Knockout ViewModel:
function InterviewViewModel() {
//Data
var self = this;
var jsonDate = #Html.Raw(Json.Encode(#Model.InterviewDate));
var date = new Date(parseInt(jsonDate.substr(6)));
self.interviewDate = ko.observable(dateFormat(date, "dd/mm/yyyy"));
self.showAdminInterviewDisplay = ko.observable(true);
self.showAdminInterviewForm = ko.observable();
self.showInterviewForm = function () {
self.showAdminInterviewDisplay(false);
self.showAdminInterviewForm(true);
$("#interviewDatePicker").datepicker({dateFormat: 'dd/mm/yy'});
};
//Operations
self.saveInterviewDate = function() {
$.ajax("#Url.Action("SaveInterview")", {
data: ko.toJSON(self),
type: "post",
contentType: "application/json",
success: function(data) {
self.showAdminInterviewDisplay(true);
self.showAdminInterviewForm(false);
}
});
};
};
ko.applyBindings(new InterviewViewModel());
Controller:
public ActionResult SaveInterview(KnockoutViewModel model)
{
if (ModelState.IsValid)
{
return Json(model);
}
return PartialView("_AdminInterview", model);
}
Instead of returning a Partial View from your Action Method, return a serialised error model to the success function in the AJAX call. The error model will contain all the errors in the ModelState.
See this post on how to get and consume the errors from Model State:
ASP.NET MVC How to convert ModelState errors to json (JK's answer)
So you would have something like:
Error Model:
public class JsonErrorModel
{
public JsonErrorModel()
{
HasFailed = true;
}
public bool HasFailed { get; set; }
public IEnumerable ErrorList { get; set; }
}
Controller:
if(ModelState.IsValid)
{
//Do whatever here
return Json(new { model });
}
return Json(new JsonErrorModel {ErrorList = ModelState.Errors()});
Success function of AJAX call:
success: function (result) {
if(result.HasFailed) {
self.showAdminInterviewDisplay(false);
self.showAdminInterviewForm(true);
DisplayErrors(result.ErrorList);
}
else {
self.showAdminInterviewDisplay(true);
self.showAdminInterviewForm(false);
}
}
So now, if the server side validation failed, the view will show the form and the validation errors.

json success and fail response in MVC

I'm practicing Ajax! I have a simple contact form and this is my actions :
public ActionResult Contact()
{
return View("Contact");
}
[HttpPost]
public ActionResult Contact(ContactViewModel contactViewModel)
{
if (ModelState.IsValid)
{
var contact = contactViewModel.ConvertToContactModel();
_contactRepository.Add(contact);
_contactRepository.Save();
return Json(new { msg = "Your contact Sent, I'll response soon." });
}
return Json("Sorry! Somthing went wrong, try again or contact again");
}
and this is my View :
#model Blog.Web.UI.ViewModels.ContactViewModel
#{
ViewBag.Title = "Contact";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div id="Contact">
#using (Ajax.BeginForm("Contact", "Home", new AjaxOptions() { OnSuccess = "Success" }))
{
<div>
#Html.LabelFor(c => c.Name)
#Html.TextBoxFor(c => c.Name)
</div>
<div>
#Html.LabelFor(c => c.Email)
#Html.TextBoxFor(c => c.Email)
#Html.ValidationMessageFor(c => c.Email)
</div>
<div>
#Html.LabelFor(c => c.Subject)
#Html.TextBoxFor(c => c.Subject)
</div>
<div>
#Html.LabelFor(c => c.Body)
#Html.TextAreaFor(c => c.Body)
#Html.ValidationMessageFor(c => c.Body)
</div>
<input type="submit" value="Send" />
}
</div>
<script type="text/javascript">
function Success(context) {
if (context[0]) {
$("#Contact").empty().html(context[1]);
}
}
</script>
Now I wanna to show the user success or failing of contact made , what's the problem of my code that doesn't work??
it is so interesting that my validation doesn't work in this case!
please help me about this , thanks
if you want an error response so be sent, then you should set the ResponseCode of the Response object to a suitable http error code, such as 400 for bad request.
You will then need to provide an error handler in the ajax.beginform to display the content you want. If you don't, it will return a responsecode of 200 and that is treat that everything is hunky dory, so your error handler won't be triggered
Contrary to Slicksim, we usually have a JSON return class defined in our application models that contains a boolean variable Success. We can then use this to have the Javascript determine if the request was successful or not.
public class JsonResponseModel(){
public bool Success {get;set;}
public string Message {get;set;}
}
public ActionResult Contact()
{
return View("Contact");
}
[HttpPost]
public ActionResult Contact(ContactViewModel contactViewModel)
{
if (ModelState.IsValid)
{
var contact = contactViewModel.ConvertToContactModel();
_contactRepository.Add(contact);
_contactRepository.Save();
return Json(new JsonResponseModel{ Success = true, Messsage = "Your contact Sent, I'll response soon." });
}
return Json(new JsonResponseModel{Success = false, Message = "Sorry! Somthing went wrong, try again or contact again"});
}
<script type="text/javascript">
function Success(response) {
if (response.Success) {
$("#Contact").empty().html(response.Message);
}
else{
alert(response.Message);
}
}
</script>
I suppose this is the route that we went instead of modifying the server headers because you may want to do something different if the validation failed on a AJAX call rather than an actual server error (HTTP Status COde 500/404/etc)

mvc3 jquery mobile how to use Html.BeginForm

I have already written an entire site in MVC3. I am trying to build the mobile version with Jquery Mobile. I haven't changed my controller code, except to add a check for whether or not it should return a mobile page. I have the following in the document head of my mobile logon page:
<head>
<title>Mobile Logon</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.2.0-alpha.1/jquery.mobile-1.2.0-alpha.1.min.css" />
<script src="http://code.jquery.com/jquery-1.7.2.min.js"></script>
$(document).bind("mobileinit", function(){
$.extend( $.mobile , {
ajaxEnabled: false
});
});
<script src="http://code.jquery.com/mobile/1.2.0-alpha.1/jquery.mobile-1.2.0-alpha.1.min.js"></script>
</head>
I have a page with a header and content. In the content, I want to let the user redirect to the register form. the following seems to work:
<form action="Register" method="get" data-ajax="false">
<button type="submit" value="Register for an account"></button>
</form>
This does not work: (the url seems correct in the browser, but all that loads is a blank, white page)
#using(Html.BeginForm("Register", "Account", FormMethod.Get, null ))
{
<button type="submit" value="Register for an account"></button>
}
When I look in the page source, I notice two differences: The first one gives a form tag with
action="Register"
while the second gives a form tag with
action="Account/Register"
The other difference is the "data-ajax=false" in the form tag.
Questions:
Am I able to use #Html.BeginForm() with Jquery Mobile? If not, how do I redirect to a different controller?
How come my code in the head section doesn't turn off the default ajax behavior of Jquery Mobile? (I tried using the form tag above without data-ajax=false, and I got the same blank, white screen as the #Html.BeginForm gave me).
EDIT: here is my logon controller code (Account controller)
public ActionResult LogOn()
{
//return View();
return SelectView("Logon", null);
}
private ActionResult SelectView(string viewName, object model, string outputType = "html")
{
if (outputType.ToLower() == "json")
{
return Json(model, JsonRequestBehavior.AllowGet);
}
else
{
#if MOBILE
return View(viewName + ".Mobile", model);
#else
if (Request.Browser.IsMobileDevice)
{
return View(viewName + ".Mobile", model);
}
else
{
return View(viewName, model);
}
#endif
}
}
here is my Register controller code: (Account controller)
public ActionResult Register(string returnUrl = "")
{
//if no return url supplied, use referrer url.
//Protect against endless loop by checking for empty referrer.
if (String.IsNullOrEmpty(returnUrl) && Request.UrlReferrer != null && Request.UrlReferrer.ToString().Length > 0)
{
return RedirectToAction("Register", new { returnUrl = Request.UrlReferrer.ToString() });
}
return View();
}

Read selected value of drop down in controller

Requirment: I have a drop down and a table on my cshtml page. The drop down displays a list of vendors and the details corresponding to selected vendor are displayed in table. I am submitting the form using jquery when the value of the drop down changes.
Problem: How to cath selected value of drop down in controller?
Code:
#Html.DropDownList("VendorList", new SelectList(Model.vendorList, "vendorId", "vendorName"))
#using (Html.BeginForm("VendorDetails", "VendorLookUp", FormMethod.Post, new { id = "vendorDetailsForm" }))
{
<div class="margin-10-top" >
<table id= "VendorDetail" class="VendorDetail">
........ details of vendor.........
</table>
</div>
}
<script type="text/javascript" charset="utf-8">
$(document).ready(function () {
$('#VendorList').change(function () {
$('#vendorDetailsForm').submit();
});
});
</script>
the code in my controller is:
[AcceptVerbs("POST")]
public ActionResult SearchResult(FormCollection collection)
{
try
{
string vendorName = collection["searchItem"].ToString();
vendorName = vendorName.Trim();
List<Vendor> vendorList = Queries.compiledVendorQuery(dbContext, vendorName).ToList<Vendor>();
if(vendorList.Count() == 0)
return View("EmptySearch");
Vendor selectedVendor = vendorList[0];
VendorDetails vendorDeatils = Queries.compiledVendorDetailsQuery(dbContext, selectedVendor.vendorId.ToString()).FirstOrDefault();
VendorResult vendorResult = new VendorResult();
vendorResult.vendorList = vendorList;
vendorResult.vendorDetails = vendorDeatils;
return View(vendorResult);
}
catch (Exception e)
{
return View("EmptySearch");
}
}
[AcceptVerbs("POST")]
public ActionResult VendorDetails(FormCollection collection)
{
**here comes the control after postback
require value of the selected item**
Vendor selectedVendor = ??
VendorDetails vendorDeatils = Queries.compiledVendorDetailsQuery(dbContext, selectedVendor.vendorId.ToString()).FirstOrDefault();
VendorResult vendorResult = new VendorResult();
vendorResult.vendorDetails = vendorDeatils;
return View(vendorResult);
}
Since you're not really using the FormCollection, you could just use an int (or whatever the ID is on your model) in your action method:
[HttpPost]
public ActionResult VendorDetails(int vendorId = 0)
{
Vendor selectedVendor = // Load from your data source using vendorId
... // Do the rest of your work
}
In your HTML, move your #Html.DropDownListFor() into your form, rename it to the argument name, then submit the form as normal. Since the display doesn't seem to have any affect on what gets sent to the server, I would pull this out and just leave the #Html.DropDownListFor() in the form:
#using (Html.BeginForm("VendorDetails", "VendorLookUp", FormMethod.Post, new { id = "vendorDetailsForm" }))
{
#Html.DropDownList("vendorId", new SelectList(Model.vendorList, "vendorId", "vendorName"))
}
<div class="margin-10-top" >
<table id= "VendorDetail" class="VendorDetail">
........ details of vendor.........
</table>
</div>
<script type='text/javascript'>
$(document).ready(function () {
$('#vendorId').change(function () {
$('#vendorDetailsForm').submit();
});
});
</script>
Edit
Take a look at this article about MVC's model binding for an idea of how vendorId gets injected from the submitted form. Basically, the binder will match property names with the name attribute (by default) to your model. In this case, our model is just an int.

Resources