I want to display success Alert pop-up or alert message after form submited and action succeded
In this example I want to show "successfully add" :
Create Action :
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(TAUX taux)
{
if (ModelState.IsValid)
{
db.TAUX.Add(taux);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.CAT_ID = new SelectList(db.CATEGORIE, "CAT_ID", "LIBELLE", taux.CAT_ID);
ViewBag.C_GARANT = new SelectList(db.GARANTIE, "C_GARANT", "LIB_ABREGE", taux.C_GARANT);
return PartialView("_Create", taux);
}
Index Action :
public ActionResult Index()
{
var taux = db.TAUX.Include(t => t.CATEGORIE).Include(t => t.GARANTIE);
return View(taux.ToList());
}
What should I add to do this ?
It's possible, for sure, but implementation details might change from technologies and app structure.
One of the most common ways for doing this (and the one I'm currently using with great success) is to receive whater-you-need-to-receive and return a JSON object with the status and/or error message, which will be used by some script on your view.
For example:
[Route(""), HttpPost]
public JsonResult DoSomethingOnTheServer(DoSomethingViewModel vm)
{
try
{
if (DoSomething(vm)) return Success();
else return Error("The server wasn't able to do something right now.");
}
catch (Exception err)
{
return Error(err.Message);
}
}
public JsonResult Success() { return Json(new { Success = true, Message = "" }); }
public JsonResult Error(string message) { return Json(new { Success = false, Message = message }); }
This way, you can do something like:
<script>
$.ajax({
url: "/",
method: "POST",
data: getMyData(),
success: function(json) {
if (json.Success) {
alert("Wow, everything was fine!");
} else {
alert(json.Message);
}
},
// This will be trigered whenever your ajax call fails (broken ISP link, etc).
error: function() {
alert("Something went wrong. Maybe the server is offline?");
}
});
</script>
Being honest with you, it's possible to submit the form (regular submit, I mean) and on the page refresh, display whatever you want.
This will, however, force you to load something extra with your view model, like an extra <script> tag or some extra <div> tags and to check for that every time.
From a usability/design point-of-view, it's a no-go. Avoid page refresh whenever possible because they give a feeling for the user that the app is either going away or that he/she is now moving outsinde the app.
Also, from a performance point-of-view, "full round-trips" to the server, consisting of sending the form data and retrieving a whole new page (with the whole layout, scripts, razor rendering/parse and all) is a massive problem just to show "success/fail" for the end-user so, again: avoid it whenever possible.
IMHO, returning either a view or a partial view only to display a message to the end-user is just wasting both yours and your end-users' link.
I used to make Ajax Form and in the OnSuccess fucntion i show message :
#using (Ajax.BeginForm("Edit1", "Availability", new AjaxOptions { HttpMethod = "POST", InsertionMode = InsertionMode.InsertBefore, UpdateTargetId = "formAddAvailabilityContainer", OnSuccess = "AddAvailabilitySuccess" }, new { #class = "AjaxForm", #id = "formAvailability_" + Model.Id }))
{
#Html.ValidationSummary(true)
#Html.HiddenFor(model => model.Id)
#Html.HiddenFor(model => model.UserId)
#Html.EditorFor(model => model.StartTime)
#Html.MyValidationMessageFor(model => model.StartTime)
#Html.EditorFor(model => model.EndTime)
#Html.MyValidationMessageFor(model => model.EndTime)
#Html.EditorFor(model => model.RecurrenceFreq)
#Html.MyValidationMessageFor(model => model.RecurrenceFreq)
#Html.TextBoxFor(model => model.EndsAfterValue, new {id="txtBoxEndsAfterValue" })
#Html.MyValidationMessageFor(model => model.EndsAfterValue)
#Html.EditorFor(model => model.EndsByDate)
<input type="submit" class="btn btn-primary" value="Save" id="btnsubmit" />
<input type="button" class="btn btn-primary btnCancelAvailability" id="0" value="Cancel">
}
<script>
function AddAvailabilitySuccess()
{
alert("Record updated successfully!");
}
</script>
I have a way to do this, using the ViewBag.
In your controller you must add:
if (ModelState.IsValid)
{
db.TAUX.Add(taux);
db.SaveChanges();
ViewBag.SuccessMsg = "successfully added";
return RedirectToAction("Index");
}
Then in the Index view:
#{
var message = ViewBag.SuccessMsg;
}
<script type="text/javascript">
var message = '#message';
if(message){
alert(message);
}
</script>
in the end you use JavaScript mixed with the MVC ViewBag :)
Related
I have a class in my project which looks like this:
public class MyClass
{
[Required]
public string keyword { get; set; }
public string saleRange { get; set; }
}
This is how the action looks like:
[HttpPost]
[ActionName("Analyze")]
public ActionResult Analyze(MyClass obj)
{
if (!ModelState.IsValid)
{
return Json("error");
}
else
{
return Json("ok");
}
}
And in jQuery:
$(document).on("click",".btnAnalyze",function() {
var data =
{
keyword: $(".keywordInput").val(),
saleRange: "1"
};
console.log($(".keywordInput").val());
$.post("/Controller/Analyze",data).done(function(){
if (data == "error") {
alert("all fields are required");
}
});
});
As you can see I'm mapping a JS object to a C# class object which I pass to my action. Now what the problem here is, even if I don't supply anything for the keyword property (ie. it's null or ""), the ModelState still shows it's property IsValid as true, but it should be set on false if I don't pass anything as keyword parameter.
This is first part of the problem, the other question I have here is how would I, If I have 10 textbox field, of which all are required. And if user enters only 1/10 of those, I would like to send a message for the first next field user has to validate in order to proceed, like "texbox #2 is required, please enter something" instead of a just general message like "all fields are required" or something like that ?
Can someone help me out with this ?
Why does the modelstate shows the it's valid even though after I dont' supply keyword parameter in the object?
#T.Jung here Is a sample of input:
<input placeholder="Enter keywords" class="form-control keywordInput" type="text" style="width:80%">
It's basically just a plain input field in html..
You can use form validation, which will perform data annotation validation on the client side and you do not have to go to the server side.
$('#btnAnalyze').on('click', function (evt) {
if ($('#YourformId').valid()) {
//Perform AJAX call
}
This way if any of the validations do not work, the form.valid() will throw the data annotation errors. So you can add Required to those fields in the models and it will ensure data is not sent if validation fails.
I would do the following:
Make sure your script bundle includes the following 2 files after your jquery and in this order:
jquery.validate.js
jquery.validate.unobtrusive.js
Create your partial / view for your form:
#model MyClassObject
<form action="/action" method="post" id="form">
<div class="row">
#Html.ValidationMessageFor(m => m.Param1)
#Html.LabelFor(m => m.Param1, new { #class = "label" })
#Html.TextBoxFor(m => m.Param1, new { #class = "textbox" })
</div>
<div class="row">
#Html.ValidationMessageFor(m => m.Param2)
#Html.LabelFor(m => m.Param2, new { #class = "label" })
#Html.TextBoxFor(m => m.Param2, new { #class = "textbox" })
</div>
<div class="row">
#Html.ValidationMessageFor(m => m.Param3)
#Html.LabelFor(m => m.Param3, new { #class = "label" })
#Html.TextBoxFor(m => m.Param3, new { #class = "textbox" })
</div>
<input type="submit" value="submit">
</form>
Do you server side validation
[HttpPost]
[ActionName("action")]
public ActionResult action(MyClassObject obj)
{
if(!ModelState.IsValid)
{
return action(); // this is your original action before you do the post
}
else
{
// do your processing and return view or redirect
return View(); // or redirect to a success page
}
}
Add the error message to your class:
public class MyClassObject
{
[Required(ErrorMessage = "Please enter a keyword")]
public string keyword { get; set; }
public string saleRange { get; set; }
}
Your js validation will be plumbed in now but you will need to stop the form from posting and check the validation before doing your ajax request:
var form = document.getElementById('form'), // get a normal js form (I do this just so I can pass in the method and action dynamically - seems better than using .attr() to get them
jqForm = $(form);
jqForm.on('submit', function(e) {
e.preventDefault();
if (jqForm.valid()) {
var formData = jqForm.serializeArray(); // I use serializeArray so I can add extra values if I need to, you can use serialize()
// formData.push({ name: this.name, value: this.value }); - optional for adding extra data
$.ajax({
url: form.action, // this can be just a specific json url if you just need to get some json - it doesn't have to be the same url as the fallback (no js url)
type: form.method,
data: formData,
success: function(result) {
// do success stuff!
}
});
}
})
You should stringify the JavaScript Object in the Jquery post
JSON.stringify(data)
If you want to do the Validation on server side:
Contoller:
[HttpPost]
[ActionName("Analyze")]
public ActionResult Analyze(Model viewModel)
{
if(viewModel.PropertyName.IsNullOrEmpty()){
{
ModelState.AddModelError("PropertyName", "The Field InputFieldName neeeds to be filled!");
}
if (ModelState.IsValid)
{
//Do what ever you want with your Inofrmation
//return a redirct or anything else
}
//If you got here some fields are not filled
return View(viewModel);
}
View:
#Html.TextBoxFor(x => x.PropertyName)
#Html.ValidationMessageFor(m => m.PropertyName, "", new { #class = "text-danger" })
//#class = "text-danger" only if you're using bootstrap
I do all of my validation this way.
I'm currently having difficulty using Ajax to update a partial view without having to refresh the whole page. I'm using MVC and entity framework to scaffold views.
I'll try and include as much as possible to help explain myself:
I have a div which is going to be used to hold a list view of all my comments
<div id="ContainAnnouncementComments"> </div>
This div gets populated using the following:
<script src="~/Scripts/jquery.unobtrusive-ajax.min.js"></script>
<script src="~/Custom_Scripts/BuildAnnouncement.js"></script>
#Scripts.Render("~/bundles/jqueryval")
$(document).ready(function () {
$.ajax({
url: '/Comments/BuildAnnouncementComment',
data: { AnnouncementId: #Model.AnnouncementId},
success: function (result) {
$('#ContainAnnouncementComments').html(result);
}
});
});
Which calls the BuildAnnouncementComment() method in my controller:
public ActionResult BuildAnnouncementComment(int? AnnouncementId)
{
return PartialView("_AnnouncementComment", db.Comments.ToList().Where(x => x.AnnouncementId == AnnouncementId));
}
I then have a second div container which is used to hold a text box for a user to enter some information which 'should' then update the ContainAnnouncementComments using Ajax replace call:
<div id="ContainAnnouncementCommentCreate">
#using (Ajax.BeginForm("AJAXCreate", "Comments", new { announcementId = Model.AnnouncementId }, new AjaxOptions
{
InsertionMode = InsertionMode.Replace,
HttpMethod = "POST",
UpdateTargetId = "ContainAnnouncementComments"
}))
{
<div class="form-group">
#Html.AntiForgeryToken()
<div class="col-md-10">
#Html.EditorFor(model => model.Message, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Message, "", new { #class = "text-danger" })
</div>
</div>
}
</div>
The Ajax method calls the AJAXCreate method in the controller:
public ActionResult AJAXCreate(int announcementId, [Bind(Include = "CommentId, Message")] Comment comment)
{
if (ModelState.IsValid)
{
comment.UserId = User.Identity.GetUserId();
comment.AnnouncementId = announcementId;
db.Comments.Add(comment);
db.SaveChanges();
}
return PartialView("_AnnouncementComment", db.Comments.ToList());
}
From here, when running, I try to create a new comment, but when submitted, instead of the partialView being updated, all that is being displayed is the partialview.
Not sure if I've explained this properly so if i'm missing any information please let me know and i'll update accordingly.
After 3 hours of staring at my code I realised that nothing was actually wrong with the implementation and all that was wrong was I hadn't installed AJAX through the NuGet manager.
Joys.
I am new to both asp.net MVC and JQuery so be gentle.
I am trying to use a HTTP Post to update my contact form, used to send an email, using AJAX. I have seen lots of posts but what I want seems specific and I cant seem to find anything relevant.
The down low: I have a layout page which has the header, renders the body and has my footer in. My footer contains the form I want to submit. I want to submit this form without refreshing the whole page. The layout page:
<div id="footer">
#{Html.RenderAction("Footer", "Basic");}
</div>
<p id="p"></p>
I have a model for this form to send an email.
namespace SimpleMemberShip.Models
{
public class EmailModel
{
[Required, Display(Name = "Your name")]
public string FromName { get; set; }
[Required, Display(Name = "Your email"), EmailAddress]
[StringLength(100, ErrorMessage = "The email address entered is not valid")]
public string FromEmail { get; set; }
[Required]
public string Message { get; set; }
}
The footer:
<h2> footer yo !</h2>
#Html.ValidationSummary()
<fieldset>
<legend>Contact Me!</legend>
<ol>
<li>
#Html.LabelFor(m => m.FromEmail)
#Html.TextBoxFor(m => m.FromEmail)
</li>
<li>
#Html.LabelFor(m => m.FromName)
#Html.TextBoxFor(m => m.FromName)
</li>
<li>
#Html.LabelFor(m => m.Message)
#Html.TextBoxFor(m => m.Message)
</li>
</ol>
<button id="submit"> Submit </button>
</fieldset>
controller:
[ChildActionOnly]
public ActionResult Footer()
{
return PartialView("~/Views/Shared/_Footer.cshtml");
}
[HttpPost]
public ActionResult Footer(EmailModel model)
{
return PartialView("~/Views/Shared/_Footer.cshtml");
}
I want to use the model validation and everything to be the same or similar as if the form was posted normally through the server.
Edit:
My new code, which works great! but it only works once, when the button is clicked again nothing happens. Anyone know why?
<script type="text/javascript">
$("#submit").click(function () {
$("#footer").html();
var url = '#Url.Action("Footer", "Basic")';
$.post(url, { FromName: $("[name=FromName]").val(), FromEmail: $(" [name=FromEmail]").val(), Message: $("[name=Message]").val() }, function (data) {
$("#footer").html(data);
});
var name = $("[name=FromName]").val();
$("#p").text(name);
});
</script>
new Edit:
did some research and using
$("#submit").live("click",function () {
instead of
$("#submit").click(function () {
seemed to do the trick.
<script type="text/javascript">
$("#submit").live("click",function () {
$('.validation-summary-errors').remove();
var url = '#Url.Action("Footer", "Basic")';
$.post(url, { FromName: $("[name=FromName]").val(), FromEmail: $("[name=FromEmail]").val(), Message: $("[name=Message]").val() }, function (data) {
$("#footer").html(data);
});
});
</script>
ended up with this but will try the "serialize()" option next time.
controller was changed to this without the [ChildActionOnly] and works perfect now
[HttpPost]
public ActionResult Footer(EmailModel model)
{
return PartialView("~/Views/Shared/_Footer.cshtml");
}
Thank you everyone that helped!
Change the [ChildActionOnly] to [HttpGet] in the controller
You can pass model data to controller by doing the following steps
1. Get the input values on click of submit and sent to the Footer action in controller
$("#submit").click(function () {
var FromEmailValue = $('#FromEmail').val();
var FromNameValue = $('#FromName').val();
var MessageValue = $('#Message').val();
var url = '#Url.Action("Footer", "Basic")';
$.ajax({
url: urlmodel,
data: { FromName: FromNameValue, FromEmail: FromEmailValue, Message: MessageValue},
cache: false,
type: "POST",
success: function (data) {
do something here
}
error: function (reponse) {
do something here
}
});
});
In the controller
``
[HttpGet]
public ActionResult Footer()
{
return PartialView("~/Views/Shared/_Footer.cshtml");
}
[HttpPost]
public ActionResult Footer(string FromName = "", string FromEmail = "", string Message = "")
{
//for ajax request
if (Request.IsAjaxRequest())
{
do your stuff
}
}
I want to update a partial view when user changes the current value of my drop down list.
With my onchange submit, the partial view does not load in div but replaces the whole page.
How can I fix it?
view:
#using (Ajax.BeginForm("GetEnvironment", new RouteValueDictionary { { "Environment", Model.Environnements } }, new AjaxOptions() { UpdateTargetId = "ExportDiv" }))
{
#Html.DropDownListForEnum(x => x.Environnements, new { onchange = "this.form.submit();" })
}
<div id="ExportDiv">
#Html.Partial("Export")
</div>
Controller :
public PartialViewResult GetEnvironment(ExampleDto model)
{
return PartialView("Export", model);
}
Export.cshtml
It looks like triggering submit on the form causes whole page to be posted instead of AJAX behavior. Try this:
#using (Ajax.BeginForm("GetEnvironment", new RouteValueDictionary { { "Environment", Model.Environnements } }, new AjaxOptions() { UpdateTargetId = "ExportDiv" },new {id = "ajaxForm"))
{
#Html.DropDownListForEnum(x => x.Environnements, new { onchange = "submitAjaxForm()" })
}
<div id="ExportDiv">
#Html.Partial("Export")
</div>
<script type="text/javascript">
$('form#ajaxForm').submit(function(event) {
eval($(this).attr('onsubmit')); return false;
});
window.submitAjaxForm = function(){
$('form#ajaxForm').submit();
}
</script>
You need to include the scripts in thier own section if you are using it.
The result should be the same than what Ufuk suggested, but did you try simply adding return false; after this.form.submit(); ?
I have a view with two partials in it that use ajax to post their forms to actions. The onsuccess callback redirects the user to another url. However I don't want this onsuccess function to be called when the modelstate is not valid. I've tried returning a 400 level error from my controller to trigger the onfailure function but it causes some weird behavior and the validation errors don't display. Here's my code
Action:
[AllowAnonymous]
[DisableCache]
public ActionResult Login(string returnUrl ="/") //This is the view that contains the two other partial views.
{
var path = VirtualPathUtility.ToAbsolute(returnUrl);
var url = new Uri(Request.Url, path).AbsoluteUri;
ViewBag.ReturnUrl = url;
return View();
}
[AllowAnonymous]
public ActionResult _LoginPartial()
{
return PartialView(new LoginModel());
}
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult _LoginPartial(LoginModel model)
{
if (ModelState.IsValid && WebSecurity.Login(model.UserName, model.Password, persistCookie: model.RememberMe))
{
return PartialView();
}
// If we got this far, something failed, redisplay form
ModelState.AddModelError("", "The user name or password provided is incorrect.");
Response.StatusCode = 400;
return PartialView(model);
}
Login View:
<hgroup class="title">
<h1>#ViewBag.Title.</h1>
</hgroup>
#section CustomScripts {
#if (ViewData.ModelState.IsValid){
<script type ="text/javascript">
function OnSuccess() {
var returnUrl = #Html.Raw(Json.Encode(ViewBag.ReturnUrl))
window.location = returnUrl;
}
function OnFailure() {
alert("Fail");
}
</script>
}
}
<section id="loginForm">
#{
if(!WebSecurity.IsAuthenticated){
<h2>Use a Creative Works account to log in.</h2>
#Html.Action("_LoginPartial")
#Html.ActionLink("Forgot your password?", "ResetPassword")
}
}
</section>
<section id ="RegisterForm">
#{
if(!WebSecurity.IsAuthenticated){
<span>Don't have an account? Make one!</span>
#Html.Action("RegisterPartial", new { returnUrl = ViewBag.ReturnUrl })
}
}
</section>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
_LoginPartial view
#model Cwo.Domain.Entities.LoginModel
#{
ViewBag.Title = "LoginPartial";
}
#using (Ajax.BeginForm("_LoginPartial",
new AjaxOptions(){UpdateTargetId = "loginForm",
InsertionMode = InsertionMode.Replace, OnSuccess = "OnSuccess", OnFailure = "OnFailure"
})) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>Log in Form</legend>
<ol>
<li>
#Html.LabelFor(m => m.UserName)
#Html.TextBoxFor(m => m.UserName)
#Html.ValidationMessageFor(m => m.UserName)
</li>
<li>
#Html.LabelFor(m => m.Password)
#Html.PasswordFor(m => m.Password)
#Html.ValidationMessageFor(m => m.Password)
</li>
<li>
#Html.CheckBoxFor(m => m.RememberMe)
#Html.LabelFor(m => m.RememberMe, new { #class = "checkbox" })
</li>
</ol>
<input type="submit" value="Log in" />
</fieldset>
}
The formatting got kinda messed up pasting in here, sorry about that. Instead of an alert("fail") response I want the validation errors to display. If there's a better way than returning a 400 level error from the action please teach me!
I think another way to word you problem is you don't want the contents of the onsuccess function to be executed? if this is the case then move your #if (ViewData.ModelState.IsValid){ ... } to inside the OnSuccess function. if state is invalid that function would have no guts so nothing gets done.
personally I like keeping javascript separate from razor...even more, the javascript should reside in its own js file. in this case you could use razor to set a bool javascript variable to a function or object constructor, which would then do your success work only if variable was true.