The code below works perfectly on IE, but when used in Chrome, it doesn't work. When I checked in debug mode, it doesn't trigger the MVC controller (but in IE it does). Does anyone know how I can get this to work in Chrome?
<input type="submit" value="Create" id="btnSaveSubmit" name="btnSubmit" class="button" onclick="if (!($('#frID').valid())) { return false; } this.disabled = true; this.value = 'Saving...'" />
Your code is just pure html & Javascript, doesn't relate to mvc.
Anyway, Chrome does not allow you to execute inline code. Inline JavaScript will not be executed
Proper way to do:
1)With javascript: Bind the event listener:
document.addEventListener('DOMContentLoaded', function() {
var btn = document.getElementById('btnSaveSubmit');
// onClick's logic below:
btn.addEventListener('click', function() {
if (!($('#frID').valid())){
return false;
}
this.disabled = true;
this.value = 'Saving...';
});
});
2) With Jquery:
$(document).ready(function() {
$("#btnSaveSubmit).on('click',function(){
if (!($('#frID').valid())){
return false;
}
this.disabled = true;
this.value = 'Saving...';
});
});
encountered this issue in Chrome as well. The cause for me: I was disabling the submit button after it was being clicked.
For Chrome, but not other browsers, the click handler seems to fire before the submit handler. For that reason, I never got to back to the controller.
The solution for me was to not disable the submit button at all after the user clicked it.
Related
I have two mutually exclusive checkboxes; that being so, I'd like each one to automatically reflect the opposite state of the other when a change is made: if checkboxA is checked, checkboxB should be, if checked, unchecked (etc., I'm sure you know what I mean).
I'm creating the checkboxes in my code-behind like so:
ckbxPaymentForSelf = new CheckBox();
ckbxPaymentForSelf.Text = "myself";
ckbxPaymentForSelf.ID = "ckbxPaymentForSelf";
this.Controls.Add(ckbxPaymentForSelf);
ckbxPaymentForSomeoneElse = new CheckBox();
ckbxPaymentForSomeoneElse.Text = "someone else";
ckbxPaymentForSomeoneElse.ID = "ckbxPaymentForSomeoneElse";
this.Controls.Add(ckbxPaymentForSomeoneElse);
Based on this, I thought maybe I could use the checkbox's Name property and set them both to the same value, something like "ckbxsSelfOrSomeoneElse" but there is no "Name" property on Checkbox available to me.
I could write some jQuery like so (pseudoscript):
$(document).on("change", '[id$=ckbxPaymentForSelf]', function () {
var ckd = this.checked;
if (ckd) // check ckbxPaymentForSomeoneElse and uncheck if it it's checked
else // check ckbxPaymentForSomeoneElse and check if it it's unchecked
});
$(document).on("change", '[id$=ckbxPaymentForSomeoneElse]', function () {
var ckd = this.checked;
if (ckd) // check ckbxPaymentForSelf and uncheck if it it's checked
else // check ckbxPaymentForSelf and check if it it's unchecked
});
...but am wondering if there is a more obvious or elegant solution to this, as this is indubitably a common requirement.
UPDATE
I tried 's answer:
$(document).on("click", '[id$=ckbxPaymentForSelf]', function () {
alert('reached onclick for ckbxpaymentforself');
$('#ckbxPaymentForSomeoneElse').prop('checked', !this.checked);
});
$(document).on("click", '[id$=ckbxPaymentForSomeoneElse]', function () {
alert('reached onclick for ckbxpaymentforsomeoneelse');
$('#ckbxPaymentForSelf').prop('checked', !this.checked);
});
...but, illogically (it seems to me and, obviously, him), it doesn't work. The strange/suspicious thing is that the alert messages are showing twice! I have to click them twice to dismiss them. Why would that be, and could that be the/a problem? I did notice that the jQuery appears twice in the "View Source" although, of course, it is in only one place in the actual source code (at the bottom of the .asxc file).
UPDATE 2
As wilusdaman suggested (make it an answer, Wilus, and I'll accept it as such), the elegantest way is to use radiobuttons instead. All that is needed is this:
rbPaymentForSelf = new RadioButton();
rbPaymentForSelf.Text = "myself";
rbPaymentForSelf.ID = "rbPaymentForSelf";
rbPaymentForSelf.GroupName = "SelfOfSomeoneElse";
this.Controls.Add(rbPaymentForSelf);
String checkboxPaymentForSomeoneElseText = "someone else";
rbPaymentForSomeoneElse = new RadioButton();
rbPaymentForSomeoneElse.Text = checkboxPaymentForSomeoneElseText;
rbPaymentForSomeoneElse.ID = "rbPaymentForSomeoneElse";
rbPaymentForSomeoneElse.GroupName = "SelfOfSomeoneElse";
this.Controls.Add(rbPaymentForSomeoneElse);
...and this jQuery, relatedly, then acts:
/* If user selects "payment for self" (they are seeking payment for themselves, as opposed to someone else), omit (invisibilize) sections 2 and 3 on the form */
$(document).on("change", '[id$=rbPaymentForSelf]', function () {
if (this.checked) {
$('[id$=panelSection2]').slideUp();
$('[id$=panelSection3]').slideUp();
$('[id$=_MailStopRow]').slideDown();
$('[id$=_AddressRows]').slideUp();
}
});
/* If user selects "payment for someone else" (they are seeking payment for someone else, as opposed to themselves), make sections 2 and 3 on the form visible */
$(document).on("change", '[id$=rbPaymentForSomeoneElse]', function () {
if (this.checked) {
$('[id$=panelSection2]').slideDown();
$('[id$=panelSection3]').slideDown();
$('[id$=_MailStopRow]').slideUp();
$('[id$=_AddressRows]').slideDown();
}
});
However, the sections that should show if the user selects "someone else" do not display the first time the user (me for now) selects the "someone else" radio button - subsequently, it does work, though...
i am able to achieve using javascript as below:
<body>
<input type="checkbox" id="one" name="one" onchange="check1()"/>
<input type="checkbox" id="two" name="two" onchange="check2()"/>
<script>
function check1()
{
if(one.checked)
{
document.getElementById("two").checked = false;
}
else
{
document.getElementById("two").checked = true;
}
}
function check2()
{
if(two.checked)
{
document.getElementById("one").checked = false;
}
else
{
document.getElementById("one").checked = true;
}
}
</script>
</body>
This can be used for each instance you have in your project, you never need to worry about mixing the logic in for each selector you wish to target. Super reusable!
Since the click event happens on the client side, heres some jQuery to fit your requirements:
$.fn.dependantCheckbox = function() {
"use strict";
var $targ = $(this);
function syncSelection(group, action) {
$targ.each(function() {
if ($(this).data('checkbox-group') === group) {
$(this).prop('checked', action);
}
});
};
$('input[type="checkbox"][data-checkbox-group]').on('change', function() {
var groupSelection = $(this).data('checkbox-group');
var isChecked = $(this).prop('checked');
syncSelection(groupSelection, isChecked);
});
}
$('input[type="checkbox"][data-checkbox-group]').dependantCheckbox();
http://codepen.io/nicholasabrams/pen/mJqyqG
I believe using a client side MVC framework is a much better elegant solution.
Eg, in AngularJs, you can bind your view (two checkboxes) to your model, and every time when you change your model, your view will be updated by framework.
In addition, I believe you can also use observationCollection to do the same on the server side (https://msdn.microsoft.com/en-us/library/ms668604(v=vs.110).aspx).
While this is elegent you will face an issue because the change event will fire for both. This would be a cartesian product as the two will start a war. the code would change the state of the other going forever, or at least causing unwanted results. Using click would be a better solution.
$(document).on("change", '#ckbxPaymentForSelf', function () {
$('#ckbxPaymentForSomeoneElse').prop('checked', !this.checked);
});
$(document).on("change", '#ckbxPaymentForSomeoneElse', function () {
$('#ckbxPaymentForSelf').prop('checked', !this.checked);
});
I suggest the following. Note the labels and use of the class vs the id to assign the event handler:
$(document).on("click", '.ckbxPaymentForSelf', function () {
$('#ckbxPaymentForSomeoneElse').prop('checked', !this.checked);
});
$(document).on("click", '.ckbxPaymentForSomeoneElse', function () {
$('#ckbxPaymentForSelf').prop('checked', !this.checked);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<input id="ckbxPaymentForSelf" class="ckbxPaymentForSelf" type="checkbox" checked/>
<label class="ckbxPaymentForSelf" for="ckbxPaymentForSelf">Payment For Self</label></br>
<input id="ckbxPaymentForSomeoneElse" class="ckbxPaymentForSomeoneElse" type="checkbox" />
<label class="ckbxPaymentForSomeoneElse" for="ckbxPaymentForSomeoneElse">Payment For Someone Else</label></br>
Note: When creating the controls server side you may want to set the
ClientIdMode="Static"
or script this way:
$('#<%= ckbxPaymentForSomeoneElse.ClientID %>').prop('checked', !this.checked);
in the script to be sure your control is referenced
Script
$(document).ready(function () {
"use strict";
$.validator.unobtrusive.parse($("#form"));
$("#submit").on("click", function () {
var form = $("#form");
form.validate();
if (form.valid()) {
}
return false;
});
});
HTML
<span>Please enter the amount of orders you wish you process:</span>
<br>
#Html.TextBoxFor(m => m.OrderModel.AmountOfOrders, new {id = "AmountOfOrders"})
#Html.ValidationMessageFor(m=> m.OrderModel.AmountOfOrders)
<input type="submit" value ="Submit" id="submit" />
I seem to have a problem with the script. The DataAnnotations for C# are showing up on the View but even if required fields are empty it will still continue to the other page.
if your button is not given
type="button"
, it will default to
type="submit"
Considering that you are using a form, the form will get submitted by the button click as your javascript is executing.
Try this.
$("#submit").on("click", function (event) {
var form = $("#form");
form.validate();
if (form.valid()) {
}
else
{
event.preventDefault();
return false;
}
});
Always use the submit event for forms, not the click event. That way it will work with key-presses:
$("#submit").on("submit", function () {
var form = $("#form");
form.validate();
if (form.valid()) {
// Proceed with submit!
}
else {
// Stop submit!
return false;
}
});
On an app I'm working on, I have a requirement that, upon clicking a certain button, validation fires on some related textboxes; if they do not pass, nothing occurs, otherwise an action that is fired from an AJAX call occurs. This AJAX call returns some message about the success of the operation.
My partial view this is occurring in looks a bit like this:
<div>
<div id='cell-phone'>
#Model.ValidationMessageFor(x=>x.Model.CellNumber)
#Model.TextBoxFor(x=>x.Model.CellNumber)
</div>
<div id='pager'>
<!-- Ditto, only x.Model.Pager; yes, some people use pagers still. -->
</div>
<div id='page-address'>
<!-- ... x.Model.PageAddress ... -->
</div>
<div id='pager-test'>
<a href='#' id='test-pager' class='button'>Test</a>
<span id='test-result'></span>
</div>
</div>
<script>
var $cellNum = $('#cell-phone input'),
$pagerNum = $('#pager input'),
$pageAddress = $('#page-address input'),
$testPager = $('#pager-test'),
$testResult = $('#test-result');
$(document).ready(function () {
$testPager.click(function () {
pagerTest();
});
});
function pagerTest() {
var args = { address: $pageAddress.val() };
$.getJSON('#Url.Action("SendTestPage")', args, function(result) {
$testResult.html(result.Message);
});
}
</script>
...down at the server level...
public JsonResult SendTestPage(string address)
{
// SNIP: Other unnecessary details.
var result = new EmailSendResult
{
success = SendEmailMethod(address)
};
result.message = result.success
? "Message sent!"
: "Couldn't send message...";
return result;
}
....
public class EmailSendResult
{
public bool success;
public string message;
}
Question: while I am able to get the message/success values back, I also need to cause the View Model's validations to fire. I don't see how to do this using an AJAX call. My suspicion is that either A) I'm using the wrong tool for the job, or B) I'm using the right tool for one job, but I need something else. What am I missing to be able to cause validations to fire?
When you click on 'test-pager' link, the action will be called but the validation of your form doesn't trigger because your link is not a submit. If you want to validation work you must have a submit button on the form. When the user clicks it the validation will fire. So change the test-pager to something like this:
<input type="submit" id="test-pager" class="button" />
Or ( if I understand question correctly) you can bind address textbox change event and within it call testPage function.
Following up from this question, I'm trying to implement an unobtrusive confirm dialog.
$(document).ready(function () {
$("[data-confirmPrompt]").click(function (event) {
var confirmPrompt = event.currentTarget.attributes['data-confirmPrompt'].value;
event.preventDefault();
$.prompt(confirmPrompt, {
buttons: { Yes: true, No: false },
callback: function (v, m, f) {
if (v) {
// User clicked Yes. Unbind handler to avoid
// recursion, then click the target element again
$(event.currentTarget).unbind('click');
event.currentTarget.click();
}
}
});
});
});
When the user has clicked on "Yes", I want the default action associated with the event to execute. I've done it above by unbinding the jQuery handler, and clicking the element again. This works fine when submitting a form or navigating to a different page - but of course does not work in AJAX-enabled pages, where I want to keep the jQuery event handler.
Is there an alternative generic way to execute the default action? Logically something like event.executeDefault().
Using the suggestion Alexey Lebedev made in his second comment, my current implementation now looks like the sample below, except that I've also added my own implementation of localization for the button labels.
Notes:
I'm now using a jqueryUI dialog widget
Note the use of .delegate so that the handler is "ajax-aware", i.e. works on elements added to the DOM after the page is loaded, e.g. as a result of an AJAX call
Uses a flag to prevent recursion when the user clicks Yes on the confirm dialog.
Uses jquery 1.6.4 and jquery-ui-1.8.16
If anyone can suggest improvements, please chime in.
<!-- Examples of usage -->
<input type='submit' data-confirm="OK to delete customer 123?" ... />
<a href="..." data-confirm="OK to navigate?" ... />
<!-- Implementation -->
<script type="text/javascript">
var confirmClickHandler = function (event) {
if ($(event.currentTarget).data('isConfirming')) return;
var message = event.currentTarget.attributes['data-confirm'].value;
event.preventDefault();
$('<div></div>')
.html(message)
.dialog({
title: "Confirm",
buttons: {
"Yes": function () {
$(this).dialog("close");
$(event.currentTarget).data('isConfirming', true);
event.currentTarget.click();
$(event.currentTarget).data('isConfirming', null);
},
"No": function () {
$(this).dialog("close");
}
},
modal: true,
resizable: false,
closeOnEscape: true
});
};
$(document).ready(function () {
$("body").delegate("[data-confirm]", "click", confirmClickHandler);
});
</script>
I'm doing something similar and this works fine for me:
$('#link').click(function(e){
if(!confirm('Are you sure you want to asdf?')){
e.preventDefault();
}
});
I honestly don't know if this answers your question, but it might help a bit.
Consider the following HTML:
<button onclick="alert('Hello world!');" class="btn">Test 1</button>
<button onclick="alert(this.className);" class="btn">Test 2</button>
I've added the following to my $(document).ready:
$('button').each(function() {
var btn = $(this);
var onClick = btn.attr('onclick');
//replace this with _this
onClick = onClick.replace(/this/g, "_this");
btn.attr('onclick', '');
btn.click(function() {
if (confirm('Do it?')) {
//set _this first!
var _this = btn[0];
eval(onClick);
}
});
});
It seems to get the job done. Check this jsFiddle example: http://jsfiddle.net/KeesCBakker/4jThg/.
EDIT
I've created something that looks more like your question: http://jsfiddle.net/KeesCBakker/hqLH5/. Just couldn't figure out which $.prompt plugin your were using, so I grabbed the first one I've found from github (this one only works in Chrome :S).
I was able to achieve this by calling event.stopPropagation() from a more specific context, and ensuring that I don't call event.preventDefault(). While you can't call the default action explicitly, you can set up the conditions so that the default action happens — and do as little or as much else as you wish.
// Normal event handler
$("[data-toggle]").click(ev => {
switchToTab(ev.currentTarget)
ev.preventDefault()
})
// Allow default handler in a specific case.
$("[data-toggle] ul a").click(ev => {
// Don't bubble the event to the less specific handler, above
ev.stopPropagation()
// An incorrect return value will also cancel the default action.
return true
})
I am creating some text boxes at runtime and I would like to change the color of the text box if the text box has been left blank
and the user submits the form.
I am using the code behind approach, this is the code I wrote in the .aspx.cs file
textBoxObj is the text box object that I create at runtime and it is the object on which I want the empty validation.
CustomValidator customValidatorObj = new CustomValidator();
customValidatorObj.ControlToValidate = textBoxObj.ID;
customValidatorObj.ClientValidationFunction = "changeColorofTextBox";
and I wrote a small Javascript snippet within the .aspx file which goes as follows (I haven't yet written the logic to change the color,
just making it not valid for now)
<script type="text/javascript">
function changeColorofTextBox(oSrc, args) {
if (args.Value.length > 0) {
args.IsValid = true;
}
else {
args.IsValid = false;
}
}
</script>
In the submit button click function of the form, I have this check if(Page.IsValid), then submit the form. However, even when the text box is empty,
the form gets submitted. It seems like the function is not even being hit. Do you have any pointers on what I am doing wrong?
I am fine with either client side or server side validation, whichever works.
EDIT
I got the error, I just had to do this
customValidatorObj.ValidateEmptyText = true;
and it started working.. Thank you, I didn't realize that the customValidator class does not try validating if the control is blank.
But I am stuck again :(
In the form, I have many text boxes. Suppose, the user entered text for 3 of the text boxes and left 2 of them blank, how do I find the text box ids so that I can change the color of only the blank ones. or, how can I write code in the javascript to find out the control ID at runtime?
I know we have to do this
document.getElementById(CONTROLIDGOESHERE).style.backgroundColor = "red";
but how I get the CONTROLIDGOESHERE value to pass to the getElementById function?
Any pointers, thanks.
Try setting customValidatorObj.EnableClientScipt = True
Assuming you are running .NET Framework version 4.0 then you could declare your textboxes using ClientIDMode="Static". That way they'll have the same ID client-side and server-side e.g.
<asp:TextBox runat="server" ID="txtName" ClientIDMode="Static" />
Then you could trigger client-side validation on a button click by declaring a button like this:
<input type="submit" id="btnSubmit" onclick="ClientSideValidation(); return false;" value="Save"/>
The JavaScript function could look something like this:
<script type="text/javascript">
function ClientSideValidation() {
var txtName = document.getElementById("txtName");
if (txtName.value.length == 0) {
txtName.style.background = "#DE0000";
}
// Check other text boxes...
}
</script>
Thank you guys, I figured it out. This code does the job for me
.aspx.cs
CustomValidator customValidator = new CustomValidator();
customValidator.ControlToValidate = textBox.ID;
customValidator.ClientValidationFunction = "changeColorofTextBox";
customValidator.ValidateEmptyText = true;
customValidator.EnableClientScript = true;
e.Item.Controls.Add(customValidator);
.aspx
<script type="text/javascript">
function changeColorofTextBox(oSrc, args) {
if (args.Value.length > 0) {
args.IsValid = true;
}
else {
var ctrlid = oSrc.id;
var validatorid = document.getElementById(ctrlid);
ctrlid = validatorid.controltovalidate;
document.getElementById(ctrlid).style.backgroundColor = "Tomato";
args.IsValid = false;
}
}
</script>