We are using HTML form validation (and we explicitly do NOT want do use jQuery validate plugin...). Currently I am able to mark invalid/empty fields after Submit. I do it this way:
if(document.addEventListener){
document.addEventListener('invalid', function(e){
e.target.className += ' invalid';
}, true);
}
But the marking remains after the user enters information to a field. How can I remove the className, let's say, onBlur?
Maybe I can just add the following CSS classes:
input:invalid:focus,
input.invalid{
border: solid 1px #f00; /* red border */
}
input:valid {
border: 1px solid #ced4da; /* reset to default border color */
}
At least this seems to work.
Are there any smarter solutions?
Add to the blur event within the invalid event handler like so:
document.addEventListener("invalid", function(e) {
const oldClassName = e.target.className;
e.target.className += "-invalid";
e.target.addEventListener("blur", function(e) {
e.target.className = oldClassName;
}, { once: true });
});
The { once: true } option at the end ensures that the event listener gets taken off once the blur happens.
The browser automatically adds/removes the :invalid pseudo selector for you https://developer.mozilla.org/en-US/docs/Web/CSS/:invalid, just style the form fields as you would for the regular case (not invalid) and invalid case (using the :invalid selector)
Related
I want to use just ONE button to control Opening and Closing an Off-Canvas Menu. So I created a Button with OpenButton class which open menu, after clicking, I remove OpenButton class and add CloseButton class, These all work like a charm, But When I call Click Event on CloseButton It doesn't work, What is the problem ?
This is my code :
$('.OpenButton').click(function() {
$(this).addClass('CloseButton');
$(this).removeClass('OpenButton');
});
$('.CloseButton').click(function() {
alert('Close');
});
Since you're adding the class dynamically, you need to use event delegation to register the same with the event handler mechanism,
$(document).on('click', ".CloseButton", function() {
alert('Close');
});
Hope this helps!
That is because the click event is bound at runtime. Since .CloseButton does not exist when the code is executed, no click event will be bound to it. One solution is to use $(document).on('click', '.CloseButton', function() {...}) to do that, but that is considered resource intensive and unnecessarily heavyhanded.
I would recommend that you do not change the class of the button instead. If you want to modify the style or appearance of the button when it's open/close, you can do it by adding classes instead of swapping classes, for example:
$('.button').click(function() {
$(this).toggleClass('is-open');
});
In this case, you can you also store the state of the button in jQuery's data object. That will abstract reading the state of an object from the DOM based on it's class:
$(function() {
$('.button').click(function() {
// Store state
if ($(this).data('is-open')) {
$(this).data('is-open', false);
alert('closing!');
} else {
$(this).data('is-open', true);
alert('opening!');
}
// Toggle class
$(this).toggleClass('is-open');
$('.toggleTarget').toggleClass('is-hidden');
});
});
.is-hidden {
display: none;
}
.button {
background-color: steelblue;
color: #fff;
display: inline-block;
padding: 10px;
}
.button.is-open {
background-color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Toggle
<div class="toggleTarget is-hidden">I am content that is toggled.</div>
my goal to this one is when u type the search bar will pop up the code below is working but i have a problem while typing into different input for example the comment input the js listen and open the search bar. is it possible when im already in a different input field the search will not pop up and show.
<style>
#searchBar { display: none; -webkit-transition: width 2s; /* Safari */ transition: width 2s;}
.search { width: 250px; height: 20px; }
</style>
<script>
window.onload = function() {
var listen = /^[a-z0-9]+$/i;
var searchInput = document.getElementById('searchInput');
var searchBar = document.getElementById('searchBar');
if ( window.addEventListener )
window.addEventListener( 'keyup', insertKey, false);
function insertKey( e ) {
// Get the character from e.keyCode
var key = String.fromCharCode( e.keyCode ).toLowerCase();
// Match the character
if( key.match(listen) ) {
// Change display: none; to display: block;
searchBar.style.display = "block";
// Append every new character
searchInput.value += key;
// Focus on input
searchInput.focus();
// Since you focused on the input you don't need to listen for keyup anymore.
window.removeEventListener( 'keyup', insertKey );
// I didn't tested with jQuery
// $('#searchBar').fadeIn();
// $('#searchBar input').append(keys);
// $('#searchBar input').focus();
}
}
};
</script>
When you add an event listener to window for the keyup event, it will trigger when a keyup is detected no matter where it originates from. You aren't being discriminatory enough about what events you're listening to.
One solution is to add the event listener directly to the input elements, so that a keyup from one element doesn't trigger another element's listener:
document.getElementById("searchInput").addEventListener("keyup", searchInputKeyHandler);
document.getElementById("commentInput").addEventListener("keyup", commentInputKeyHandler);
// etc.
This works but is a bit weird. If all you're doing is listening for a user typing in an input HTML element, then a better event to listen for is input which triggers whenever an input element has its value changed.
document.getElementById("searchInput").addEventListener("input", searchInputKeyHandler);
document.getElementById("commentInput").addEventListener("input", commentInputKeyHandler);
// etc.
Some elements can also listen for a change event; do some research and see what event is most appropriate for your use case.
I am trying to make a "composed component" which consists of an input field and a button.
I have the following jsfiddle as example:
http://jsfiddle.net/stt0waj0/
<div id="myComponent">
<input type="text" onBlur="this.style.border='1px solid red';">
<button type="button" onClick="alert('Hello World');">ClickMe</button>
</div>
The behavior I want is that when I leave the input field without writing any content, I get a validation error (red border in this case). This already works in the fiddle (content validation is not the scope of the question).
However, when I leave the input field by pressing the button, I will open a dialog which allows to select values for the input field, so in that case, I don't want the validation to run.
So, the concrete question about the fiddle: Can I click the input field, and then click the button and not have a red border? But, if I click the input field, and then click somewhere else, I want the red border (any onBlur except when button was clicked).
Is this possible without dirty tricks?
Things I want to avoid:
Set a timer on the first event to wait for the second (Reason: performance)
Make the onClick event always reset the red border on the text field (Reason: gui glitches)
Just to make it clear on what I'm looking for and why this question is interesting: the onBlur event is fired before the onClick event. However, I normally would need the onBlur to know that the onClick comes next, which is not possible. That's the point of the question.
Imagine a date picker which validates on empty field, when the field has focus and you press the calendar, you will get a validation error even though you're selecting a date. I want to know if there is an elegant way to handle such cases.
To make this work, you can postpone your validation function if user pressed the button.
Below is sample code and fiddle to show what i mean.
* Updated the fiddle to use select dropdown instead of a button *
Fiddle Demo
input.error {color: red; border: 1px solid red;}
<div id="myComponent">
<input id="btn" type="text" onBlur="inputBlur()">
<select type="button" data-btn="btn" onclick="inputButtonClick()" onchange="selectChange()" onblur="selectBlur()">
<option value="">choose</option>
<option value="item1">item1</option>
<option value="item2">item2</option>
<option value="item3">item3</option>
</select>
</div>
window.validate = function(input) {
//do your validation
var val;
console.log("Validating");
val = input.val();
if ( !val || !val.length) {
input.addClass("error");
console.log("Something is invalid");
} else {
//all good
console.log("All valid");
}
//clear error after x time to retry
setTimeout(function() {
$(".error").removeClass("error");
$("input").removeAttr("data-btn-active") ;
}, 3000);
}
window.selectBlur = function() {
var input = $("#" + $(event.target).attr("data-btn"));
validate(input);
}
window.selectChange = function() {
var input = $("#" + $(event.target).attr("data-btn"));
console.log("change", $(event.target).val() );
input.val( $(event.target).val() );
validate(input);
}
window.inputButtonClick = function() {
var input = $("#" + $(event.target).attr("data-btn"));
input.attr("data-btn-active", "true");
console.log("inputButtonClick",input );
}
window.inputBlur = function() {
var input = $(event.target);
//give a bit of time for user to click on the button
setTimeout(function() {
if (!input.attr("data-btn-active" ) ) {validate(input);}
}, 100);
}
$(document).ready(function() {
});
I have a jsfiddle Here: http://jsfiddle.net/zAFND/616
Now if you open up fiddle in IE (I use IE9) and firefox, if you double click on a check box button, it turns it on but does not turn it off. But if you open it up in opera, safarai and chrome, it works fine if you double click or click in quick succession.
My question is how to allow quick succession clicks to work correctly in firefox and IE9?
Code:
HTML:
<div id="ck-button"><label>
<input type="checkbox" name="options[]" id="optionA" value="A" /><span>A</span></label>
</div>
CSS:
#ck-button {
margin:8px;
background-color:#EFEFEF;
border:1px solid #D0D0D0;
overflow:auto;
float:left;
position: relative;
}
#ck-button label {
float:left;
width:4.0em;
cursor:pointer;
}
#ck-button label span {
text-align:center;
padding:3px 0px;
display:block;
}
#ck-button label input {
position:absolute;
top:-20px;
}
#ck-button input:checked + span {
background-color:green;
color:white;
}
Jquery/javasscript:
$(document).ready(function(){
$("body").css("-webkit-user-select","none");
$("body").css("-moz-user-select","none");
$("body").css("-ms-user-select","none");
$("body").css("-o-user-select","none");
$("body").css("user-select","none");
});
This is a bug in Firefox. See Bug 608180 - Double/rapid clicking a checkbox label does not work as expected
IE has, for historical reasons (but fixed in more recent versions), a bugged event model that skips the second mousedown and click events on a double click. See bug 263 - beware of DoubleClick in IE.
I've made a plugin that fixes some bugs in jQuery UI button widget as well as working around the Firefox bug not long ago, shouldn't be hard to adapt it to your non-jQuery UI buttons.
Extracted the important part and adapted it for nested checkboxes inside labels:
(function () {
var mdtarg, //last label mousedown target
mdchecked, //checked property when mousedown fired
fixedLabelSelector = '.fixedLabelCheckbox'; //edit as you see fit
$(document).on('mousedown', fixedLabelSelector, function (e) {
//only left clicks will toggle the label
if (e.which !== 1) return;
mdtarg = this;
mdchecked = this.control ? this.control.checked : $(this).find('input')[0].checked;
//reset mdtarg after mouseup finishes bubbling; prevents bugs with
//incorrect mousedown-mouseup sequences e.g.
//down IN label, up OUT, down OUT, up IN
$(document).one('mouseup', function () {
mdtarg = null;
});
}).on('mouseup', fixedLabelSelector, function (e) {
if (e.which !== 1) return;
if (mdtarg === this) {
var ch = this.control || $(this).find('input')[0];
//the click event is supposed to fire after the mouseup so
//we wait until mouseup and click finish bubbling and check if it
//had the desired effect
setTimeout(function () {
if (mdchecked === ch.checked) {
//else patch it manually
ch.checked = !ch.checked;
$(ch).change();
}
}, 0);
}
});
}());
Fiddle tested in Firefox.
You have to add the fixedLabelCheckbox class to all labels containing checkboxes that you'd like to fix with the code above.
It will work regardless of where you put the script and it also fixes dynamically added checkboxes as long as the label has the corresponding delegated class/selector.
Note that if you're using other libraries, this may not fire the change handlers bound outside of jQuery.
If you don't feel like adding extra classes to your markup, you can use this version (more code and less performance):
(function ($) {
function getControl(lbl) { //fallback for non-HTML5 browsers if necessary
return lbl.control || (lbl.htmlFor ? $('input[id="'+lbl.htmlFor+'"]')[0] : $(lbl).find('input')[0]);
}
var mdtarg, //last label mousedown target
mdchecked; //checked property when mousedown fired
$(document).on('mousedown', 'label', function (e) {
//only left clicks will toggle the label
if (e.which !== 1) return;
var ch = getControl(this);
if (!ch || ch.type !== 'checkbox') return;
mdtarg = this;
mdchecked = ch.checked;
//reset mdtarg after mouseup finishes bubbling; prevents bugs with
//incorrect mousedown-mouseup sequences e.g.
//down IN label, up OUT, down OUT, up IN
$(document).one('mouseup', function () {
mdtarg = null;
});
}).on('mouseup', 'label', function (e) {
if (e.which !== 1) return;
if (mdtarg === this) {
var ch = getControl(this);
//the click event is supposed to fire after the mouseup so
//we wait until mouseup and click finish bubbling and check if it
//had the desired effect
setTimeout(function () {
if (mdchecked === ch.checked) {
//else patch it manually
ch.checked = !ch.checked;
$(ch).change();
}
}, 0);
}
});
}(jQuery));
Fiddle
As you can see from the code above, this version should work with both label's for attribute as well as nested inputs inside the label, without adding any extra markup.
About disabling selection: you can either put the user-select in the CSS as commented in your question, or, if browsers that don't support the user-select are also concerned, apply this answer on all labels that you want to have selection disabled.
You could add browser detection and then, if IE or Firefox, add the ondblclick event via JS to invert the checkbox.
You can't just set it unconditionally, since some browsers (Safari, Chrome) transmit two clicks and a dblclick, while others (IE, Firefox) transmit only one click and one dblclick. On the former, the two click events will invert the field twice. On the latter, only one click event fires and thus the field is only inverted once; to mitigate this, you need to make dblclick invert the field so that two clicks invert it an even number of times.
Hope this helps!!
I have a textfield and at the moment i disable the submit button when the textfield does not hold three charactes. What i want to do now is also outline the textfield bold red and still have the submit button disabled, however i cannot seem to be able to outline the textfield and disable the submit button at the same time.
my code for disabling the submit button is as follows is it possible to be able to outline the textfield when the length is < 3 in this function to?
thankfull for any help
$(function() {
$('input[name="updateMessage"]').attr('disabled','disabled');
$('input[name="selectMessageForUpdate"]').keyup(function(){
if($('input[name="selectMessageForUpdate"]').val().length < 3)
{
$('input[name="updateMessage"]').attr('disabled','disabled');
}
else
{
$('input[name="updateMessage"]').removeAttr('disabled');
}
});
});
He wants to style the textarea, not the submit button. Just add a class to your textarea with the specified markup and remove it when the input is valid. Also check if the input is more than just whitespace.
$(function() {
$('input[name=updateMessage]').attr('disabled','disabled');
$('input[name=selectMessageForUpdate]').keyup(function(){
if($('input[name=selectMessageForUpdate]').val().length < 3)
{
$('input[name=updateMessage]').attr('disabled','disabled');
$('input[name=selectMessageForUpdate]').addClass('someClass');
}
else
{
$('input[name="updateMessage"]').removeAttr('disabled');
$('input[name=selectMessageForUpdate]').removeClass('someClass');
}
});
});
Add to your css:
input.indicated_textfield { border: 2px solid red; }
Add the addClass and removeClass lines to your Javascript code:
$(function() {
$('input[name="updateMessage"]').prop('disabled', true);
$('input[name="selectMessageForUpdate"]').keyup(function(){
if($('input[name="selectMessageForUpdate"]').val().length < 3)
{
$('input[name="updateMessage"]').prop('disabled', true);
$('input[name="selectMessageForUpdate"]').addClass('indicated_textfield');
}
else
{
$('input[name="updateMessage"]').prop('disabled', false);
$('input[name="selectMessageForUpdate"]').removeClass('indicated_textfield');
}
});
});
Add the border css property along with attr('disabled')
Add a class to define the red border, in your css:
textarea[name=selectMessageForUpdate].disabled { border:5px solid red }
your js:
$(function() {
$('input[name="updateMessage"]').attr('disabled','disabled');
$('textarea[name="selectMessageForUpdate"]').keyup(function(){
if($(this).val().length < 3)
{
$('input[name="updateMessage"]').attr('disabled','disabled');
$(this).addClass('disabled'); // ADD THIS
}
else
{
$('input[name="updateMessage"]').removeAttr('disabled');
$(this).removeClass('disabled'); // ADD THIS
}
});
});
I created a js fiddle and it seems to work...
http://jsfiddle.net/tmjaF/8/