Html.BeginForm how to avoid multiple form submission? - javascript

We have the following code for registration page
#using (Html.BeginForm(MVC.Account.Register(Model.ReturnUrl), FormMethod.Post, new { #id = "register-form" }))
{
<div class="control-group clear">
#Html.LabelFor(m => m.Email)
#Html.TextBoxFor(m => m.Email, new { type = "email", #class = "forbid-lt-gt" })
<span class="hint raise">Will be user as Username.</span>
<div class="error">#Html.ValidationMessageFor(m => m.Email)</div>
</div>
<div class="control-group clear">
#Html.LabelFor(m => m.Password)
#Html.PasswordFor(m => m.Password)
<span class="hint raise">Length between 6 and 10 characters</span>
<div class="error">#Html.ValidationMessageFor(m => m.Password)</div>
</div>
<div class="control-group clear">
#Html.LabelFor(m => m.ConfirmPassword)
#Html.PasswordFor(m => m.ConfirmPassword)
<div class="error">#Html.ValidationMessageFor(m => m.ConfirmPassword)</div>
</div>
<div class="control-group action">
<button class="btn primary" type="submit">
<span>Sign up</span>
</button>
</div>
<div class="clear"></div>
}
And the file formBlocker.js to prevent multiple button click
$(function() {
$('form').one('submit', function () {
$(this).find('button[type="submit"]').attr('disabled', 'disabled');
});
//Enable submit button if data has changed
$('form').live("input", function () {
$(this).find('button[type="submit"]').removeAttr('disabled');
});
});
Usually all is fine, but sometimes it doesn't work and after user clicks several times on button the form can be sent several times to server. Early we had issue that after a click on submit button in IE form was sent to server twice. Now we don't have this issue but it was't fixed.

live is dead. dead. It was deprecated in 2.7 and removed in 2.9. DEAD!
I would use this approach:
var serializedData;
$(function () {
$('form').submit(function () {
var tempSerializedData = $(this).serialize();
if (tempSerializedData != serializedData)
serializedData = tempSerializedData;
else
return false;
});
});

Try this Not sure but this is working for me
$('form').one('submit', function () {
$(this).find('button[type="submit"]').attr('disabled', 'disabled');
setTimeout(function () {
$(this).find('button[type="submit"]').attr('disabled', 'disabled');
}, 20);
});

Related

Ajax Success does not render partial view

I have placed a partial view into a modal to update a password like so:
<div class="modal fade" id="modalPassword" tabindex="-1" role="dialog"
aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-body">
<div class="modal-content">
<div id="message"></div>
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title" id="myModalLabel">Change Password</h4>
</div>
<div class="modal-
<div id="passwordForm">
#{
#Html.Action("ChangePassword","Account");
}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
This is my partial view:
#model WebApplication1.Models.ViewModel.ChangeUserPassword
#{
Layout = null;
}
<script src="~/Scripts/jquery-1.10.2.min.js"></script>
<script src="~/Scripts/jquery.validate.min.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>
<form id="form">
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset id="submitPasswordForm">
<div class="col_full">
#Html.LabelFor(model => model.OldPassword, htmlAttributes: new { #class = "capitalize t600" })
#Html.TextBoxFor(model => model.OldPassword, null, new { #class = "sm-form-control", id = "txtOldPassword" })
#Html.ValidationMessageFor(model => model.OldPassword)
</div>
<div class="col_full">
#Html.LabelFor(model => model.ChangedPassword, htmlAttributes: new { #class = "capitalize t600" })
#Html.TextBoxFor(model => model.ChangedPassword, null, new { #class = "sm-form-control", id = "txtChangedPassword" })
#Html.ValidationMessageFor(model => model.ChangedPassword)
</div>
<div class="col_full">
#Html.LabelFor(model => model.ConfirmPassword, htmlAttributes: new { #class = "capitalize t600" })
#Html.TextBoxFor(model => model.ConfirmPassword, null, new { #class = "sm-form-control", id = "txtConfirmPassword" })
#Html.ValidationMessageFor(model => model.ConfirmPassword)
</div>
<div class="modal-footer">
<button type="button" class="btn btn-warning" data-dismiss="modal">Cancel</button>
<input type="submit" value="Save Changes" class="btn btn-primary" id="btn_save_password" />
</div>
</fieldset>
</form>
When I click the "btn_save_password", I invoke the onclick event like so:
$("#btn_save_password").click(function (event) {
event.preventDefault();
var data = $("#submitPasswordForm").serialize();
$.ajax({
type: "POST",
url: "#Url.Action("ChangePassword", "Account")",
data: data,
success: function (result) {
$("#passwordForm").empty();
//$("div").remove("#passwordForm");
addHtml(result);
},
error: function () {
$("#passwordForm").html("Error occured");
}
});
});
function addHtml(htmlString) {
$("#msg").html(htmlString);
}
Then it invokes a method in my controller "ChangePassword"
[Authorize]
public ActionResult ChangePassword()
{
return PartialView();
}
[HttpPost]
public ActionResult ChangePassword(ChangeUserPassword password)
{
if (ModelState.IsValid)
{
var cookie = HttpContext.Request.Cookies["Sys_user_id"];
var um = new UserManager();
if (cookie != null && um.GetAccountPassword(Convert.ToInt32(cookie.Value), password.OldPassword))
{
um.ChangeUserPassword(password, Convert.ToInt32(cookie.Value));
}
else
{
ModelState.AddModelError("","Wrong current password");
}
}
else
{
ModelState.AddModelError("","Error");
}
return View();
}
The "ChangePassword" method invokes the PartialView "ChangePassword.html" like so:
[Authorize]
public ActionResult ChangePassword {
return PartialView();
}
I can view the partial view on the modal and I am able to successfully update the database. But the problem is, I want to be able to send a successful message or error message into the modal when it is successful or not. Upon submission, whether it has updated the database or not, it refreshes the page and the modal is gone. I want to be able to get the message into the modal.
Your help is greatly appreciated.
EDIT --
I can now see the validation message in the Modal but it only works once. As soon as I click the "btn_save_password" again, the page refreshes.
Add two <div> sections containing your messages (Successs and Failed) with the hide class in the partial view. After Ajax Submission, Add class Show for the suitable div.
eg:
<div class="alert alert-danger text-center hide" role="alert"id="FailedMesssage">
Failed....!!!
</div>
<div class="alert alert-success text-center hide" role="alert" id="successMesssage">
success....!!!
</div>
<button type = "button" value="Submit" onclick ="Test()"/>
Set Var Value as 0 or 1 using ajax code then try following script
<script>
function Test()
{
var value =1;
if(value == 1)
{
$("#successMesssage").addClass("show").removeClass("hide");
}
else
{
$("#FailedMesssage").addClass("show").removeClass("hide");
}
}
</script>

Javascript on editor template

I have a page to add outcomes to a areas on a form. I utilise Editor templates to group the outcomes into areas and allow the outcome to be selected from a drop down list. I'd like to show an optional comments box for two of the 3 possible outcomes.
The main page is the following:
#model DBS.ViewModels.OutcomeQuestionnaireVM
#{
ViewBag.Title = "Outcomes";
}
<h2>Add Outcomes</h2>
#if (Model.Error == true)
{
<h3 class="danger">You MUST select an outcome for at least 1 area.</h3>
}
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.HiddenFor(x => x.DebriefId)
<hr />
#Html.EditorFor(m => m.Groups, new { outcomes = Model.Outcomes })
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Next" class="btn btn-default" />
</div>
</div>
</div>
}
The group editor template is:
#model DBS.ViewModels.OutcomeQuestionGroupVM
#{
Layout = null;
}
<h4>#Html.DisplayFor(m => m.Name)</h4>
#Html.EditorFor(m => m.Questions, new { outcomes = ViewData["outcomes"] })
The final editor template for the outcome is:
#model DBS.ViewModels.OutcomeQuestionVM
#{
Layout = null;
}
<div class="form-group">
<div class="row">
<div class="col-md-4">
#Html.DisplayFor(m => m.Question)
</div>
<div class="col-md-4">
#Html.HiddenFor(m => m.ID)
#Html.DropDownListFor(m => m.OutcomeId, (SelectList)ViewData["outcomes"], "Please Select if applicable", new { #class = "form-control", #id = "OutcomeId" })
#Html.ValidationMessageFor(m => m.OutcomeId, "", new { #class = "text-danger" })
</div>
<div class="col-md-4" id="Comments">
#Html.HiddenFor(m => m.Comments)
#Html.TextAreaFor(model => Model.Comments, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.Comments, "", new { #class = "text- danger" })
</div>
</div>
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
<script type="text/javascript">
$(document).ready(function ()
{
document.getElementById('Comments').hide;
});
$(function () {
$(".DropChange").change(function () {
var valone = $('#OutcomeId').val();
if (valone == 1 || valone == 2)
{
$('#Comments').show();
}
else if (valone == 3)
{
$('#Comments').hide();
}
else
{
$('#Comments').hide();
}
});
});
</script>
}
However javascript doesn't do anything.
Sections are not supported in partial views, which is fortunate in your case or you would be adding multiple inline copies of each script in the jqueryval bundle as well as your own script (one each time the template is added).
Your also generating invalid html because of the duplicate id attributes generated by new { id = "OutcomeId" } and <div class="col-md-4" id="Comments"> which means the script would never have worked anyway.
You are also generating a hidden input for Comments before the textarea for the same property, which means that when the form is submitted, the value of Comments will be the initial value (as generated by #Html.HiddenFor(m => m.Comments)) and the value of the <textarea> would be ignored.
Its the responsibility of the view to include the scripts, not the partial, so move the scripts to the main view (or layout) and use class names and relative selectors.
Your html in the template should be
<div class="row">
<div class="col-md-4">
#Html.DisplayFor(m => m.Question)
</div>
<div class="col-md-4">
#Html.HiddenFor(m => m.ID)
// add class name to handle the .change() event
#Html.DropDownListFor(m => m.OutcomeId, (SelectList)ViewData["outcomes"], "Please Select if applicable", new { #class = "form-control outcome" })
#Html.ValidationMessageFor(m => m.OutcomeId, "", new { #class = "text-danger" })
</div>
<div class="col-md-4" class="comments"> // use class name
#Html.TextAreaFor(model => Model.Comments, htmlAttributes: new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.Comments, "", new { #class = "text- danger" })
</div>
</div>
then include css to initially hide all comments
.comments {
display: none;
}
and the script in the main view
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
<script type="text/javascript">
$(".outcome").change(function () {
var valone = $(this).val();
// get the associated comment
var comment = $(this).closest('.row').find('.comments');
if (valone == 1 || valone == 2) {
comment.show();
} else {
comment.hide();
}
});
</script>
}
Note it was not clear what $(".DropChange") was referring to but I assume its the dropdownlist in your template (which I gave class="outcome")

.submit(function ()) inside my modal popup is not working, and my modal popup will send normal http post request

I am working on an asp.net mvc web application. on my main view i got the following create link:-
<a class="btn btn-success" data-modal="" href="/Staff/Create" id="btnCreate">
<span class="glyphicon glyphicon-plus"></span>
</a>
<!-- modal placeholder-->
<div id='myModal' class='modal fade in'>
<div class="modal-dialog">
<div class="modal-content">
<div id='myModalContent'></div>
</div>
</div>
</div>
and i have the following script:-
$(function () {
$.ajaxSetup({ cache: false });
$("a[data-modal]").on("click", function (e) {
$('#myModalContent').load(this.href, function () {
$('#myModal').modal({
keyboard: true
}, 'show');
$('#myModalContent').removeData("validator");
$('#myModalContent').removeData("unobtrusiveValidation");
$.validator.unobtrusive.parse('#myModalContent');
bindForm(this);
});
return false;
});
});
function bindForm(dialog) {
$('#myModalContent', dialog).submit(function () {
if ($('#myModalContent').valid()) {
$('#progress').show();
$.ajax({
url: this.action,
type: this.method,
data: $(this).serialize(),
success: function (result) {
if (result.success) {
$('#myModal').modal('hide');
$('#progress').hide();
//location.reload();
alert('www');
} else {
$('#progress').hide();
$('#myModalContent').html(result);
bindForm();
}
}
});
}
else {
return false;
}
});
}
Now when i click on the Create link the Create action method that will return the following partial view, which will be rendered inside a modal popup :-
#model SkillManagement.Models.Staff
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Staff</h4>
<hr />
#Html.ValidationSummary(true)
<div class="form-group">
#Html.LabelFor(model => model.GUID, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.GUID)
#Html.ValidationMessageFor(model => model.GUID)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.UserName, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.UserName)
#Html.ValidationMessageFor(model => model.UserName)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.IsExternal, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.IsExternal)
#Html.ValidationMessageFor(model => model.IsExternal)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.FirstName, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.FirstName)
#Html.ValidationMessageFor(model => model.FirstName)
</div>
</div>
//code goes here
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
till now i have every thing working well, the Get Create action method will be called and the partial view will be rendered inside a modal popup.
but now inside my partial view if i click on "Create" button , the Post create action method will be called but not due to the javascript code . and when i check Request.IsAjax() inside my Post create action method, i got that it is not an ajax request which means the partial view send a normal Post http and not ajax request as defined inside the script,, can anyone advice what is wrong in my current approach ?
Thanks
as you can see you just pass the #myModalContent node to the bindForm function, and jQuery selector looks for
// will never find #myModalContent
$('#myModalContent', myModalContentDOMElement).submit(function () {
Instead you should do something like this
$('form', dialog).submit(function (e) {
e.preventDefault(); // stop the default form submit action
You are loading your form into the page via ajax, but the form you are loading is a regular html form if you want the form itself to use ajax, I believe are looking for #Ajax.BeginForm().
msdn documentation
#using (Ajax.BeginForm({objectparams})){
...

Infinity Ajax Request When Drop Change in Knockout MVC

I am using Knockout MVC in my project. I try to pass the viewModel to when Drop Down changing . but when I try this method call several times and the alert "ok" invoke continuesley. Can any one please help me on this??
$(function () {
$('#rmch').change(function () {
$.ajax({
url: '#Url.Action("DropChange", "Home")',
type: 'POST',
data: ko.mapping.toJSON(viewModel),
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function (data) {
if (data.redirect) {
location.href = resolveUrl(data.url);
}
else {
//ko.applyBindings(viewModel, document.getElementById("p_scentsFH"));
alert("Ok");
ko.mapping.fromJS(data, viewModel);
}
},
error: function (error) {
alert("There was an error posting the data to the server: " + error.responseText);
},
});
});
});
My Json Method
public JsonResult DropChange(HotelModel hotelmod)
{
//hmodel.RoomModel = new List<RoomModel>();
//for (int i = 1; i <= hmodel.NoOfRooms; i++)
//{
// hmodel.RoomModel.Add(new RoomModel { adultsDrp = ListItems.GetList(1, 6), childDrop = ListItems.GetList(0, 5) });
// //hmodel.RoomModel.Add(new RoomModel { });
//}
var jjj = JsonConvert.SerializeObject(hotelmod);
return Json(hotelmod);
}
My View
<div class="search-tab-content">
<div class="tab-pane fade active in" id="hotels-tab">
<form id="searchfrm">
<div class="title-container">
<h2 class="search-title">Search and Book Hotels</h2>
<p>We're bringing you a new level of comfort.</p>
<i class="soap-icon-hotel"></i>
</div>
<div class="search-content">
<h5 class="title">Where</h5>
<label>Your Destination</label>
#ko.Html.TextBox(m => m.Destination, new { #class = "input-text full-width", #placeholder = "Any destination, country, city code" })
#ko.Html.Hidden(new { #Id = "DesCode" }).Value(m => m.DesCode)
<hr>
<h5 class="title">When</h5>
<div class="row">
<div class="col-xs-4">
<label>Check In</label>
<div class="datepicker-wrap">
#ko.Html.TextBox(m => m.CheckInDate, new { #class = "input-text full-width" })
</div>
</div>
<div class="col-xs-4">
<label>Check Out</label>
<div class="datepicker-wrap">
#ko.Html.TextBox(m => m.CheckOutDate, new { #class = "input-text full-width" })
</div>
</div>
<div class="col-xs-4">
<label>ROOMS</label>
<div class="selector">
#ko.Html.DropDownList(m => m.RoomList, new { #class = "full-width jkl", #id = "rmch" }, "Text", "Value").Value(m => m.NoOfRooms)
</div>
</div>
</div>
<hr>
<div id="p_scentsFH">
#using (var rmModel = ko.Foreach(m => m.RoomModel))
{
<h5 class="title">Room 1</h5><div class="row">
<div class="col-xs-3">
<label>ADULTS</label>
<div class="selectorgen">
#rmModel.Html.DropDownList(m => m.adultsDrp, new { #class = "full-width" },"Text","Value").Value(m=>m.adultscount)
</div>
</div>
<div class="col-xs-3">
<label>KIDS</label>
<div class="selectorgen">
#rmModel.Html.DropDownList(m => m.childDrop, new { #class = "full-width" }, "Text", "Value").Value(m => m.childcount)
</div>
</div>
<div class="agecls">
#using(var chage=rmModel.Foreach(m=>m.childage))
{
<div class="col-xs-3">
<label>Child</label>
<div class="selectorgen">
#chage.Html.DropDownList(m => m.ageDrop, new { #class = "full-width" },"Text","Value").Value(m=>m.Age)
</div>
</div>
}
</div>
</div><hr>
}
</div>
<button type="submit" class="full-width uppercase">Search Cheap Hotels</button>
</div>
}
</form>
</div>
</div>
I believe that when the redirection did not happen then on else part your view model binding is causing your dropdown value to get changed and hence the dropdown on change event triggers again and again. Make sure you are not changing the selected item of your dropdown from ajax call.

Form Resetting is not working using jquery

I want to reset the form after calling an ajax function.
This is the code i gave in the jquery:
$("#frm_silder").reset();
Here frm_silder is the id of form. But when I'm using this code i got an eorror message like this.
$("#frm_silder").reset is not a function
In my html i give the id to form like this:
<form name="frm_silder" id="frm_silder" method="post">
So what is the problem in my code?
In jQuery
$('#frm_silder')[0].reset();
in Javascript
document.getElementById('frm_silder').reset()
You need to reset each element individually. Jquery does not have a function reset() that works on a form. reset() is a Javascript function that works on form elements only. You can however define a new jquery function reset() that iterates through all form elements and calls the javascript reset() on each of them.
$(document).ready(function(){
$('a').click(function(){
$('#reset').reset();
});
});
// we define a function reset
jQuery.fn.reset = function () {
$(this).each (function() { this.reset(); });
}
Demo
Alternatively, if you don't want to define a function, you can iterate through the form elements
$(document).ready(function() {
$('a').click(function() {
$('#reset').each(function() {
this.reset();
});
});
});
Demo
Source
I followed the solution given by #sameera. But it still throw me error.
I changed the reset to the following
$("form#frm_silder")[0].reset();
Then it worked fine.
You can use the following.
#using (Html.BeginForm("MyAction", "MyController", new { area = "MyArea" }, FormMethod.Post, new { #class = "" }))
{
<div class="col-md-6">
<div class="col-lg-3 col-md-3 col-sm-3 col-xs-12">
#Html.LabelFor(m => m.MyData, new { #class = "col-form-label" })
</div>
<div class="col-lg-9 col-md-9 col-sm-9 col-xs-12">
#Html.TextBoxFor(m => m.MyData, new { #class = "form-control" })
</div>
</div>
<div class="col-md-6">
<div class="">
<button class="btn btn-primary" type="submit">Send</button>
<button class="btn btn-danger" type="reset"> Clear</button>
</div>
</div>
}
Then clear the form:
$('.btn:reset').click(function (ev) {
ev.preventDefault();
$(this).closest('form').find("input").each(function(i, v) {
$(this).val("");
});
});

Categories

Resources