Trying to implement 'required' attribute on IE<11 and Safari.
Here is the script I am using to try to accomplish this, but it isn't working. Looking for feedback or a slap in the face if necessary. The form id = "sendit"
$("#sendit").submit(function() {
if (!attributeSupported("required") || ($.browser.safari)) {
$("#sendit [required]").each(function(index) {
if (!$(this).val()) {
alert("Please fill all required fields.");
return false;
}
});
}
});
This is an old post, but I see it wasn't answered. The problem with your code is that you have the "return false" within the "each" function. That breaks out of the each loop but doesn't stop the form submit. I would just remove the browser checks since any browser that supports html5 form validation will pass the test. So you should be able to change the code to this:
$("#sendit").submit(function() {
var valid = true;
$("#sendit [required]").each(function(index) {
if (!$(this).val()) {
alert("Please fill all required fields.");
valid = false
$(this).focus();
return false;
}
});
if (!valid) {
return false;
}
// anything else that need to be done on submit
});
Note that I added a line to focus the form field as well.
Related
I have an HTML5/Bootstrap form with hidden fields:
style="display: none"
which i show/hide via jQuery:
show() | hide()
For field validation i use the attribute required.
I want to have all my hidden fields as required but when some of them don't appear then the form can't proceed to submission.
Any thoughts about how can i have validation enabled only to fields displayed by user selections?
You can use this trick:
inside HTML form:
<input type="text" name="username" required="required" class="input-hidden">
CSS class:
.input-hidden{
height:0;
width:0;
visibility: hidden;
padding:0;
margin:0;
float:right;
}
You can add a class name for all the required attributes in the html:
<input type="text" name="first_name" class="card-payment-info" required>
<input type="text" name="last_name" class="card-payment-info" required>
and, from js event like a click, you can enable or disable the required attributes:
// disable require:
$(".card-payment-info").attr('required', false);
// enable require
$(".card-payment-info").attr('required', true);
Add a class .hideable to your hideable required inputs.
Then use these functions instead of your show() and hide():
function show1() {
//Your show() code here
$('.hideable').attr('required', 'required');
}
function hide1() {
//Your hide() code here
$('.hideable').removeAttr('required');
}
1 - Change the form to "novalidate"
2 - Catch the submit event
3 - Force the browser to check individually each visible input with input.reportValidity()
$('form')
.attr('novalidate', true)
.on('submit', function(){
var isValid = true;
$('input:visible,select:visible,textarea:visible', this).each(function() {
// report validity returns validity of input and display error tooltip if needed
isValid = isValid && this.reportValidity();
// break each loop if not valid
return isValid;
});
// do not submit if not valid
return isValid;
})
I've made a JQuery tool for this that also uses a mutation observer to automatically apply on dynamically created forms.
https://github.com/severinmoussel/VisibilityFormValidator/blob/master/VisibilityFormValidator.js
I wrote a drop-in replacement for the built-in show() and hide() that removes required on hide and restores them back on show (for all child elements).
(function ($) {
var oldShow = $.fn.show;
$.fn.show = function () {
oldShow.apply(this, arguments); //run the original "show" method
this.find("[notrequired]").prop("required", true).removeAttr("notrequired");
return this;
};
var oldHide = $.fn.hide;
$.fn.hide = function () {
oldHide.apply(this, arguments); //run the original "hide" method
this.find("[required]").prop("required", false).attr("notrequired", "1");
return this;
};
})(jQuery);
UPD: published as a gist here in case anyone wants to add anything https://github.com/alex-jitbit/jquery-required-visibility/blob/main/showhide.js
You can add pointer-events: none;, so the user can't click on the hidden element and also the cursor doesn't change when you hover it. As #DeadApe answered in this question
https://stackoverflow.com/a/65356856/6938902
One solution is to write your own validation-function:
This function checks all textareas and inputs in the default way, but first check if the input is displayed.
function validateFormOnlyVisableInputs(elForm) {
var inputs = elForm.querySelectorAll("input, textarea");
for (var i = 0; i < inputs.length; i++) {
console.log(i);
// display:none inputs ignorieren
if (inputs[i].offsetParent === null) continue;
if (!inputs[i].checkValidity()){
inputs[i].reportValidity();
return false;
}
}
return true;
}
You have to add an eventlistener to the submit-button and call the valdation function:
// this is out of a class, so you have to remove this...
// if you have problems you can write me ;)
this.elSendButton = this.elForm.querySelector("Button");
this.elSendButton.addEventListener("click", async (e) => {
e.preventDefault();
if (validateFormOnlyVisableInputs(this.elForm)) {
this.elForm.submit();
...
I hope I am clear enough with this request for assistance, as it is hard to explain and I can't post all the code here. I have downloaded code to enable TinyMCE to be used in a NgRepeat with AngularJS:
angular.module('ui.tinymce', [])
.value('uiTinymceConfig', {})
.directive('uiTinymce', ['uiTinymceConfig', function (uiTinymceConfig) {
uiTinymceConfig = uiTinymceConfig || {};
var generatedIds = 0;
return {
require: 'ngModel',
link: function (scope, elm, attrs, ngModel) {
var expression, options, tinyInstance;
// generate an ID if not present
if (!attrs.id) {
attrs.$set('id', 'uiTinymce' + generatedIds++);
}
options = {
// Update model when calling setContent (such as from the source editor popup)
setup: function (ed) {
ed.on('init', function (args) {
ngModel.$render();
});
// Update model on button click
ed.on('ExecCommand', function (e) {
ed.save();
ngModel.$setViewValue(elm.val());
if (!scope.$$phase) {
scope.$apply();
}
});
// Update model on keypress
ed.on('KeyUp', function (e) {
ed.save();
ngModel.$setViewValue(elm.val());
if (!scope.$$phase) {
scope.$apply();
}
});
},
mode: 'exact',
elements: attrs.id
};
if (attrs.uiTinymce) {
expression = scope.$eval(attrs.uiTinymce);
} else {
expression = {};
}
angular.extend(options, uiTinymceConfig, expression);
setTimeout(function () {
tinymce.init(options);
});
ngModel.$render = function () {
if (!tinyInstance) {
tinyInstance = tinymce.get(attrs.id);
}
if (tinyInstance) {
tinyInstance.setContent(ngModel.$viewValue || '');
}
};
}
};
}]);
var gwApp = angular.module('gwApp', ['ui.tinymce']);
I don't really understand this code, but it works fine initially. My page starts with a list of Posts. I click on 'Show Reply' for the first post, and using NgSwitch the multiple replies become visible (nested NgRepeat). I submit a new reply message (the reply text is entered using tinymce) using a RESTful API service and a http call (too much code to post here). Then after clicking the submit button for the new reply message, the NgSwitch kicks in again unexpectedly to make the replies no longer visible. When I expand the replies again, the tinymce is just a regular textarea again, and the proper editor is gone.
I know this is not very clear, but I'm hoping someone can make sense of what I've written and can help me solve this problem..
I was having the same problem using ng-switch and ng-show so i added:
scope.$watch('onHidden()',function(){ tinymce.editors = [] });
after the setTimeout function.
Also replace the
ed.on('init',function(args){ ngModel.$render(); });
with
ed.on('init',function(args){ ed.setContent(ngModel.$viewValue); });
and remove the $render function.
This is the link to the working code in JsFiddle
I'm new to Mootools and I have found that I have to use the click element but I'm not 100% sure where I am meant to put it in the below code:
function setInStockOption (labels, e) {
active = false;
labels.some (function (item,index) {
if(item.hasClass ('selected')) {
if(item.hasClass ('unavailable')) {
item.removeClass('selected');
item.addClass ('unselected');
active = true;
} else {
return true;
}
}
if(active) {
if (!item.hasClass ('unavailable')) {
e.target = this;
item.fireEvent ('click', e);
active = false;
return true;
}
}
});
}
window.addEvent('load', function(e) {
var labels = $$('div.option-radios label.radio');
setInStockOption(labels, e);
});
I basically need to add the class selected on click instead. At the moment this script is adding the selected class to the first child of Radio in the html and then when you click on others it'll add the class selected. I basically want all the classes to be unselected when the page loads
.
Any ideas?
You'll want something like this:
window.addEvent('domready', function(e) {
$$('div.option-radios label.radio').each(function(label, i) {
label.addEvent('click', function(event) {
event.target.toggleClass('selected');
});
});
});
Note that this uses the Array.each method instead of Array.some. The latter doesn't do what you expect. It then registers a click event on every label which simply toggles the selected class on the event target.
Then you can add other initialization code to the each loop and more logic to the click event handler.
I also used the domready event which is usually preferred over load since it fires earlier.
Here's a fiddle to play around with.
I cannot believe I am still have basic programming problems... I know the basics, but still have a hard time implementing the logic I think of. Anyways
I am building this basic Chrome Extension that has one JavaScript file and it does work! The only issue is that once I click the icon it is forever on, that is until I remove it. I want to add a basic toggle functionality, but I am having difficulty getting a working prototype. Here is a couple of my ideas:
var toggle == 1; // or true, i.e. clicked
if (functionName() == 1) {
function functionName() {
Do whatever it is when clicked;
blah blah blah;
} else if (functionName() == 0) {
Turn off;
} else {};
}
switch(toggle)
{
case 1:
Do whatever it is when clicked;
blah blah blah;
break;
case 2:
Turn off;
break;
default:
error;
break;
}
If both if statement and switch statement had a different order, say case 1 and 2 were swapped, I do not think it would be a difference. I do not think a switch statement would be the best way because there is no more than two options, on or off.
What about a while loop to change the conditions of the extension? I do know the modulo operator, and code could be written like:
1 % 2 = False,
2 % 2 = True,
3 % 2 = False, etc
Then a basic if-statement could work....
something like:
var i = 1;
while (i % 2 == 1) {
Do whatever it is when clicked;
blah blah blah;
i++;
}
Does anybody have an idea of the best way to do this? I have played with the jQuery .toggle() event, but I do not think this would make since. I have nothing in the html document and only a JavaScript file. It makes no since loading the library and then using the jQuery selector$("chrome.browserAction.onClicked.addListener(function)") when simple JavaScript can be used. Plus I do not even know if that would be the right selector...
Any help would be great, thanks in advance.
For the record I found the sample extensions useless when it comes to something that should not be complicated.
Thanks!
UPDATE code with my function in background.js:
function trigger() {
chrome.browserAction.onClicked.addListener(function(tab) {
chrome.windows.onFocusChanged.addListener(function(windowId) {
if (windowId != chrome.windows.WINDOW_ID_NONE) {
chrome.tabs.query({ active:true, windowId:windowId }, function(tabs) {
if (tabs.length == 1) {
var tab = tabs[0];
chrome.tabs.reload(tab.id);
}
});
}
});
});
}
var functionOn = false;
chrome.browserAction.onClicked.addListener(function() {
if (functionOn === false) {
document.addEventListener('DOMContentLoaded', function() {
trigger();
});
functionOn = true;
} else if (functionOn === true) {
document.addEventListener('DOMContentLoaded', function() {
//nothing...
});
functionOn = false;
}
The if statement does not work at the moment, my exstension works with this call instead of the if statement at the end:
document.addEventListener('DOMContentLoaded', function() {
trigger();
});
It's hard to give you a super detailed answer without knowing exactly what is supposed to be toggled, but in a nutshell you just need to add something like this to your background script:
var functionOn = false;
chrome.browserAction.onClicked.addListener(function() {
if (functionOn === false) {
doSomething();
functionOn = true;
} else {
functionOn = false;
// Don't do anything.
}
});
By putting the variable "functionOn" in the background page the state is persistent. You may already be aware of this, but to create a background script you simply add this to the manifest file:
"background": {
"scripts": ["background.js"]
},
It's hard to tell what you're trying to do with the toggle, but the doSomething() would basically be whatever action you're trying to perform, whether it's injecting code via a content script or showing a popup, etc.
I'm using Malsup's excellent Form plugin to dynamically load search results onto the same page.
It works great with a standard form submit, however I have 2 select elements in my form and would love for the results to update as the select is changed.
My code at the moment is thus:
$(document).ready(function() {
var options = {
target: '#bands-results',
beforeSubmit: showRequest
};
$('#bandsearch').ajaxForm(options);
});
// Show loading message and submit form
function showRequest(formData, jqForm, options) {
$('#bands-results').prepend('<span>Searching</span>');
return true;
}
I haven't seen other examples that do the same.
Help appreciated.
Got it licked with this
$(document).ready(function() {
$("#genre-filter").change(function() {
$("#band_search").submit();
});
// bind to the form's submit event
$('#band_search').ajaxForm({
beforeSubmit: showRequest,
target: '#band_list',
success: function() {
$('#premlim').hide();
}
});
})
function showRequest(formData, jqForm, options) {
return true;
}