jQuery validation with submit button disabled - javascript

I made some sort of form validation. User can input name of group and group description. With jQuery I'm validating if group name is empty or not, if empty submit button should be disabled. Now I have problems with disabling submit button. If I click on input tag where group name is, then validation is ok, and submit button is disabled, but if I just click on submit button, without touching anything else, then jQuery skip validation and fires submit button although name of group is empty.
I tried setting input tag in focus with jQuery but it only works if I actually click on that input tag.
Submit button is 'saveGroup' button.
Can someone tell me how to invoke click event on this input tag, or maybe I can use some other validation tehnique.
<div class="newGroupDiv">
<label>Title: </label><input type="text" id="groupTitle" onblur="checkTitle();"><br>
<label>Description:</label><br>
<textarea id="groupDescription"></textarea><br><br>
<button id="saveGroup">Save</button>
<button id="cancelGroup">Cancel</button>
<label id="groupError"></label>
</div>
---------------------------------------------------------------------------------
$("#saveGroup").click(function(){
var variable = checkTitle();
if(variable == true){
if($("#groupError").html() == ""){
$(".columns").append('<ul class="'+ $("#groupTitle").val() +'"><li class="naslov">'+ $("#groupTitle").val() +'</li></ul>');
$("ul").sortable({containment : 'document',
tolerance: 'pointer',
cursor: 'pointer',
revert: 'true',
opacity : 0.6,
connectWith : "ul",
placeholder: 'border',
items : 'li:not(.naslov)',
start : function(){
check = false;
$(".readContent").fadeOut(300);
}, stop : function(){
check = true;
}}).disableSelection();
$.post("addGroup.php", {'title' : $("#groupTitle").val(), 'description' : $("#groupDescription").val(),
'color' : $("#colorHex").html(), 'color2' : $("#colorHex2").html()}, function(){
window.location.reload();
});
}
}
});
--------------------------------------------------------------------------------
var checkTitle = function(){
$.post("checkTitle.php", {'title' : $("#groupTitle").val()}, function(data){
if(data == 'exist') $("#groupError").html("Group already exists");
if(data == 'no title') $("#groupError").html("Group title can't be empty");
else if(data == 'ok') $("#groupError").html("");
});
return true;
}
With this 'variable' I tried to accomplish some sort of callback wait, so when this variable gets result from function it should continue with rest of code, but I'm not sure if it works.

You would be better of switching the way you do things here. First of, as I said, make sure you do the "isEmpty" check without performing any ajax calls. Javascript is perfectly capable of doing so itself.
Secondly, instead of checking the HTML inside your element, you'd be better of checking the result of your checkTitle() function. Because there might be a slight possibility the if($("#groupError").html() == ""){ fails because there is still some HTML detected.
The above comments result in this javascript:
function checkTitle() {
$groupTitle = $('#groupTitle').val();
if($groupTitle == "") {
$("#groupError").html("Group title can't be empty");
return false;
} else {
$.post("checkTitle.php", {'title' : $groupTitle }, function(data){
if(data == 'exist') {
$("#groupError").html("Group already exists");
return false;
} else if(data == 'ok') {
$("#groupError").html("");
return true;
}
});
}
}
Now the result of the checkTitle() function can be used in your final check that you perform onBlur and onClick. Let's continue with your HTML:
<div class="newGroupDiv">
<label>Title: </label>
<input type="text" id="groupTitle" onblur="checkTitle();"><br>
<label>Description:</label><br>
<textarea id="groupDescription"></textarea><br><br>
<button id="saveGroup">Save</button>
<button id="cancelGroup">Cancel</button>
<label id="groupError"></label>
</div>
Just a little suggestion is to use a div instead of a label to show your groupError in, I understand right now this is for demo purposes only so it's just a little sidenote.
I'm not 100% possitive this solution will work, however, what I think is causing the issue is the default behaviour of the button you're using. Since the script is completely relying on the ajax call, my guess is that you have to prevent the default from happening as such:
$('#saveGroup').click(function(e) {
e.preventDefault();
});
You could give the script below a shot, hopefully it works. I can't test it because of the ajax calls. But I'll make a jsFiddle with some test data in a minute:
$("#saveGroup").click(function(e){
e.preventDefault();
var formValidation = checkTitle();
// formValidation is only true in case no errors occured
// Therefor making your #groupError check useless
if(formValidation == true) {
// Reset the #groupError html content
$('#groupError').html('');
// insert your other jQuery code here
}
});
a jsFiddle: http://jsfiddle.net/8bJAc/
As you can see onBlur the data is checked (please not there's a random factor that simulates true/false for your ajax call) and after submitting you can see either a success or error message.

Related

How to make a tag description required

I'm pretty new to WordPress, but basically what I'm trying to achieve is to make a tag's description a required field on my custom theme for WordPress 4.5.2
I've tried three approaches, but all of them failed so if anyone WordPress expert out there could guide me would be nice.
Approach #1
functions.php
I've tried to 'edit' the hook when the edit_tag_form_fields and add_tag_form hook is called, then modify via Javascript
function require_category_description(){
require_once('includes/require_category_description.php');
}
add_action('edit_tag_form_fields', 'require_category_description');
add_action('add_tag_form', 'require_category_description');
require_category_description.php
<script>
jQuery(document).ready(function(){
var description = jQuery('#tag-description');
if(!description) description = jQuery('#description');
if(description){
description.parents('form').submit(function(){
if(description.val().trim().length < 1){
console.log('Please enter a description...');
return false;
}
});
}
});
</script>
It was not working, the form was submitting even though the description field was empty, and above all, the console.log inside the event listener never happened. I've tried to log the description variable to make sure it's going inside the if case. Therefore, I assumed the form was never submitting, and the whole 'submission' is done via Ajax, on the button click.
Approach #2
The functions.php remains the same as approach #1, but I've made some changes Javascript wise to target the button click event instead of the form submit event.
require_category_description.php
<script>
jQuery(document).ready(function(){
var description = jQuery('#tag-description');
if(!description) description = jQuery('#description');
if(description){
var button = description.parents('form').find('#submit');
button.on('click', function(e){
if(description.val().trim().length < 1)
console.log('Please enter a description...');
e.preventDefault();
return false;
});
}
});
</script>
The form is however still submitting, but this time, I see the console log message.
Please enter a description...
My theory is that WordPress is binding an event to the button's click before my event, so it's processing the built-in event with Ajax before going to my custom click event.
Approach #3
require_category_description.php
I've tried to unbind the click events from my button before adding my own click event.
<script>
jQuery(document).ready(function(){
var description = jQuery('#tag-description');
if(!description) description = jQuery('#description');
if(description){
var button = description.parents('form').find('#submit');
button.unbind('click');
button.on('click', function(e){
if(description.val().trim().length < 1)
console.log('Please enter a description...');
e.preventDefault();
return false;
});
}
});
</script>
The result is the same as approach #2. The form is still submitting, but I see the console log message.
Edit tag:
When editing tag, WordPress call wp_update_term. But there're no filters or AJAX call, so we must use get_term() which is called by wp_update_term():
add_filter('get_post_tag', function($term, $tax)
{
if ( isset($_POST['description']) && empty($_POST['description']) ) {
return new \WP_Error('empty_term_name', __('Tag description cannot be empty!', 'text-domain'));
} else {
return $term;
}
}, -1, 2);
We also need to update term_updated_message to make the error clear:
add_filter('term_updated_messages', function($messages)
{
$messages['post_tag'][5] = sprintf('<span style="color:#dc3232">%s</span>', __('Tag description cannot be empty!', 'text-domain'));
return $messages;
});
Because WordPress hardcoded the notice message div, I used inline css to make the error look like a waring. Change it to your preference.
Add new tag:
The AJAX request calls wp_insert_term so we can use pre_insert_term filter. Try this in your functions.php
add_filter('pre_insert_term', function($term, $tax)
{
if ( ('post_tag' === $tax) && isset($_POST['description']) && empty($_POST['description']) ) {
return new \WP_Error('empty_term_name', __('Tag description cannot be empty!', 'text-domain'));
} else {
return $term;
}
}, -1, 2);
Here I used the built-in empty_term_name error to show notice message but you should register your own one.
Also, take a look at wp_ajax_add_tag to fully understand what we're doing.
Demo:
It's Ajax so you cannot rely on submit event, here is a solution, how you can do.
All you want to do is include form-required class to the parent tag of the particular element, but there is kick on it. their validateForm check only on input tags not on textarea so I have implemented an idea, it works.
Try this
function put_admin_script() { ?>
<script>
jQuery(document).ready(function(){
var description = jQuery('#tag-description');
if( !description ) {
description = jQuery('#description');
}
if( description ) {
description.after( $('<p style="visibility:hidden;" class="form-field form-required term-description-wrap"><input type="text" id="hidden-tag-desc" aria-required="true" value="" /></p>') );
}
description.keyup(function(){
$("#hidden-tag-desc").val( $(this).val() );
});
jQuery("#addtag #submit").click(function(){
console.log("Not empty"+description.val().trim().length);
if( description.val().trim().length < 1 ) {
description.css( "border", "solid 1px #dc3232" );
} else {
description.css( "border", "solid 1px #dddddd" );
}
});
});
</script>
<?php
}
add_action('admin_footer','put_admin_script');

Controller stops updating value after the value is changed

I'm trying to use angular to change the css class of an element when a user inputs data, both after a button click and in real time as the user is typing in data.
HTML:
<input type="text" class="defaultClass" ng-class="{true: 'errorClass',
false:'defaultClass'}[updateInput()]" ng-model="inputOne">
CSS:
.defaultClass {border: 1px solid #ccc;}
.errorClass {border: 1px solid #FF0000;}
After a button is pressed, the controller checks if the model of the element is blank and if so, makes the function return true and therefore changes the css class in the ng-class to show an error.
$scope.calcButton = function (){
if ($scope.inputOne === "" || $scope.inputOne === undefined) {
$scope.updateInput = function() {
return true;
};
} else {
$scope.updateInput = function() {
return false;
};
}
};
Outside of the button click function, I have the following code in the same controller that should be watching the status of $scope.inputOne and returning true or false based upon the status of the input:
$scope.updateInput = function() {
if ($scope.inputOne === "") {
return true;
} else {
return false;
}
};
And it works fine as long as I don't click the button, but once the value is changed by the button press the controller stops checking if the input field is empty or filled.
This is a problem because I want to have the error messages fade away as the user types in data after a button press that threw errors, but I can't change the css by user input at this point.
Why does it do this? How can I ensure that the controller still keeps track of what's going on in the input field after the button click?
Try like this
ng-class="{'errorClass' : !inputOne,'defaultClass': inputOne }"
or like this
ng-class="!inputOne ? 'errorClass' : 'defaultClass'"
'',null,NaN,undefined,0 etc considered false in JavaScript.
just check model has value or not.
It'll work through two way binding . don't need method for this to check

js checkbox NOT set a custom value if not checked

I am working on a form that someone else created that passes through information to Salesforce. But regardless of where it sends values to, the checkbox doesnt seem to behave as it should.
No matter checking or unchecking the checkbox, it will always output the 'xxx' value.
The javascript sets the value of another checkbox inside salesforce based on the first checkbox. If that checkbox is checked, set the 'optin' value to true, if not false.
I feel I need another line of code that says: if checkbox is checked then value=xxx. if not checked, nothing. Then based on that, the other if else can be run.
here is the html:
<input type="checkbox" value="xxx" id="industry_optin" name="industry_optin"> YES
This is the js: (it is part of a bigger part of js, so there is no close bracket)
$(document).ready(function() {
$('#industry_optin').on('change', function() {
if ($(this).prop('checked') === true) {
$('#optin').prop('checked', true);
} else {
$('#optin').prop('checked', false);
}
});
Your code has errors because of }); ending of code.
$(document).ready(function() {
$('#industry_optin').on('change', function() {
if ($(this).prop('checked') === true) {
$('#optin').prop('checked', true);
} else {
$('#optin').prop('checked', false);
}
});
});
Fiddle

javascript onChange computation - show only one alert

I didnt know how to properly name my question, but here goes.
In my html i have a "form" but not
<form></form>
.It is just a couple of selects, radio buttons and text inputs.
I enter, check and select values and according to these values, some computation is done. This "form" is computing on every keydown, blur, change. So when I change one value it will immediately recalculate the results with new value.
I would like to alert the user, when he didnt fill any of the necessary inputs. Here is how it works now (this is in a separate .js file)
function calculator() {
// Here is code that gathers the data from html
// and here are also some computations (many if-s)
// The code is too long to be putted here
}
$(function () {
$('select, input').on('keydown blur change', calculator);
});
I tried to put a if statement inside of my calculator function:
function calculator() {
// Here is code that gathers the data from html
// and here are also some computations (many if-s)
// The code is too long to be putted here
if (val1 == '' && sadzba == '' && viem == '' && ...) {
alert('You have to fill all necessary fields!')
}
}
This obviously caused, that the alert was popped every time I enter / choose new value, because at the beginning all variables are empty / with no value.
So how can I achieve, this situation: User fills in the "form" except of (for example)one value and only then will the alert pop up.
Than you.
I suggest to do the check on submit and return false if one of the fields is empty, preventing the form to be submitted.
$('form').on('submit', function () {
if (val1 == '' || sadzba == '' || viem == '') {
alert('You have to fill all necessary fields!');
return false;
} else { return true; }
});
Use a different event handler for the onblur event since that's when the cursor has left the input box. (It also prevents the event handler from firing all the time. That's a pretty expensive process and it can slow your page down)
$('select, input').on('blur', didTheyLeaveTheFieldEmpty);
Hope I understood you right, you can try this:
function calculator(event) {
if ( $(event.target).val().length == 0 ) {
alert('fill the field');
}
}
$('select, input').on('keyup', calculator);
even if you don't want a form with a submit buton you can create a button
and trigger your code on it's click
<input type="button" class="calculate">
$(function () {
$('.calculate').on('click', calculator);
});

Javascript Bind on Blur, Both 'if indexOf' and 'else' Performed

HTML
<!-- Contents of div #1 -->
<form id="6hgj3y537y2biacb">
<label for="product_calendar" class="entry_label">Calendar</label>
<input type="text" name="product_calendar" class="entry" value="" />
</form>
<form id="pyc2w1fs47mbojez">
<label for="product_calendar" class="entry_label">Calendar</label>
<input type="text" name="product_calendar" class="entry" value="" />
</form>
<form id="kcmyeng53wvv29pa">
<label for="product_calendar" class="entry_label">Calendar</label>
<input type="text" name="product_calendar" class="entry" value="" />
</form>
<!-- Contents of div #2 -->
<div id="calendar_addRemove"> <!-- CSS >> display: none; -->
<div id="calendar_add">
<label for="calendar_add" class="calendar_addLabel">Add Occurrence</label>
<input type="text" name="calendar_add" class="calendar_addInput" value=""/>
</div>
<div id="calendar_remove">
<label for="calendar_remove" class="calendar_removeLabel">Remove Occurrence</label>
<input type="text" name="calendar_remove" class="calendar_removeInput" value=""/>
</div>
</div>
Javascript
// Complete behavioral script
$(function() {
$('input[name=product_calendar]').css({ 'color': '#5fd27d', 'cursor': 'pointer' }).attr({ 'readonly': 'readonly' }); // Additional formatting for specified fields
$('input[name=product_calendar]').focus(function() { // Focus on any 'input[name=product_calendar]' executes function
var product_calendar = $(this); // Explicit declaration
var attr_val = $(product_calendar).attr('value');
$('#calendar_addRemove input').attr({ 'value': '' }); // Clear input fields
$('#calendar_addRemove').fadeIn(500, function() { // Display input fields
$('input[name=calendar_add]').blur(function() { // After value entered, action occurs on blur
alert('Blur'); // Added for testing
var add_val = $('input[name=calendar_add]').attr('value');
if (add_val != '') {
alert('Not Blank'); // Added for testing
var newAdd_val = attr_val + ' ' + add_val;
$(product_calendar).attr({ 'value': newAdd_val });
$('#calendar_addRemove').fadeOut(500);
}
else {
alert('Blank'); // Added for testing
$('#calendar_addRemove').fadeOut(500);
}
});
$('input[name=calendar_remove]').blur(function() { // After value entered, action occurs on blur
alert('Blur'); // Added for testing
var remove_val = $(this).attr('value');
if (remove_val != '') {
alert('Not Blank'); // Added for testing
if (attr_val.indexOf(remove_val) != -1) {
alert('Eval True'); // Added for testing
var newRemove_val = attr_val.replace(remove_val, '');
$(product_calendar).attr({ 'value': newRemove_val });
$('#calendar_addRemove').fadeOut(500);
}
else {
alert('Eval False'); // Added for testing
$('#calendar_remove').append('<p class="error">Occurrence Not Found</p>');
$('.error').fadeOut(1500, function() { $(this).remove(); });
}
}
else {
alert('Blank'); // Added for testing
$('#calendar_addRemove').fadeOut(500);
}
});
});
});
});
I've added a few alerts to see the order this script is performing in. When I enter 1234 into input[name=calendar_add] and blur, the alerts come up as expected. Then, when I proceed and enter 1234 into input[name=calendar_remove] and blur, this script throws up alerts in the following order: Blur, Not Blank, Eval False, Blur, Not Blank, Eval True - If I repeat this process, the occurrence of my alerts double every time (both add and remove), however keeping the same order (as if in sets).
I think the issue is multiple value re-declaration of the variable attr_val in the DOM, but I'm not quite sure how to revise my script to alleviate this issue.
It doesn't. That is not possible.
So, there are some possible reasons that it might seem so:
The code that actually runs doesn't look like that. It might be an older version that is cached, or you are looking in the wrong file.
The code runs more than once, that way both execution branches may run. (Although I can't really see any possibility for that here.)
You are misinterpreting the result, and whatever you see that leads to the conclusion that both branches have to be executed, is in fact caused by some other code.
You could use a debugger to set breakpoints in the code. Set one breakpoint before the condition, and one in each branch. Then you will see if the code runs twice, once or not at all.
Edit:
The alerts that you added to the code shows that the event is actually called twice, and the first time the values are not what you think that they are.
Add some code to try to find out where the event is invoked from. Catch the event object by adding it to the function signature: .blur(function(e) {. Then you can use e.currentTarget to get the element that triggered the event, and display some attributes from it (like it's id) to identify it.
Edit 2:
I am curios about this line:
$(product_calendar).attr({ value: newRemove_val });
Do you create the variable product_calendar somewhere, or did you mean:
$('input[name=product_calendar}').attr({ value: newRemove_val });
Edit 3:
Seeing the complete code, the cause of the double execution is clear. You are adding even handlers inside an event handler, which means that another handler is added every time.
The reason for attr_val not working properly is because it's created as a local variable in one function, and then unsed in another function.
Add the blur handlers from start instead, and they occur only once. Declare the variable outside the function.
Some notes:
You can use the val function instead of accessing the value attribute using the attr function.
When you assign $(this) to product_calendar, it's a jQuery object. You don't have to use $(product_calendar).
The removal doesn't match complete values, so you can add 12 and 2, then remove 2 and you get 1 and 2 left.
(this is a dummy text, because you can't have a code block following a list...)
// Complete behavioral script
$(function() {
// declare variables in outer scope
var attr_val;
var product_calendar;
$('input[name=product_calendar]')
.css({ 'color': '#5fd27d', 'cursor': 'pointer' })
.attr('readonly', 'readonly') // Additional formatting for specified fields
.focus(function() { // Focus on any 'input[name=product_calendar]' executes function
product_calendar = $(this); // Explicit declaration
attr_val = product_calendar.val();
$('#calendar_addRemove input').val(''); // Clear input fields
$('#calendar_addRemove').fadeIn(500); // Display input fields
});
$('input[name=calendar_add]').blur(function() { // After value entered, action occurs on blur
var add_val = $(this).val();
if (add_val != '') {
product_calendar.val(attr_val + ' ' + add_val);
}
$('#calendar_addRemove').fadeOut(500);
});
$('input[name=calendar_remove]').blur(function() { // After value entered, action occurs on blur
var remove_val = $(this).val();
if (remove_val != '') {
if (attr_val.indexOf(remove_val) != -1) {
product_calendar.val(attr_val.replace(remove_val, ''));
$('#calendar_addRemove').fadeOut(500);
} else {
$('#calendar_remove').append('<p class="error">Occurrence Not Found</p>');
$('.error').fadeOut(1500, function() { $(this).remove(); });
}
} else {
$('#calendar_addRemove').fadeOut(500);
}
});
});
OK, I think I understand the issue now.
Every time you do a focus on the product_calendar elements, you do a fadeIn on the #calendar_addRemove element. Every time you do that fadeIn, you use its callback to bind new blur handlers to the calendar_add and calendar_remove elements. That means that over time, those elements will have multiple blur handlers (all executing the same logic.) That can't be what you want.
In the script below, I've pulled out the nested handlers so that they're only bound once to each element. Note that:
product_calendar is declared (as null) at the top of the anonymous function, and then updated by the focus handler on the product_calendar element. I think this results in correct behavior.
attr_val is declared and assigned locally in both of the blur handlers. Again, I think this results in the correct behavior: If you were to declare it outside of the blur handlers (as product_calendar is declared), then you might accidentally use old values when you access it.
I'm still not sure exactly how this code is supposed to function, but this script performs in a way that I'd consider "reasonable".
(By the way, production code should probably allow for whitespace at the beginning and end of the input strings.)
$(function() {
var product_calendar = null;
$('input[name=product_calendar]').css({ 'color': '#5fd27d', 'cursor': 'pointer' }).attr({ 'readonly': 'readonly' }); // Additional formatting for specified fields
$('input[name=calendar_add]').blur(function() { // After value entered, action occurs on blur
alert('Blur'); // Added for testing
var add_val = $('input[name=calendar_add]').attr('value');
if (add_val != '') {
alert('Not Blank'); // Added for testing
var attr_val = $(product_calendar).attr('value');
var newAdd_val = attr_val + ' ' + add_val;
$(product_calendar).attr({ 'value': newAdd_val });
$('#calendar_addRemove').fadeOut(500);
}
else {
alert('Blank'); // Added for testing
$('#calendar_addRemove').fadeOut(500);
}
});
$('input[name=calendar_remove]').blur(function() { // After value entered, action occurs on blur
alert('Blur'); // Added for testing
var remove_val = $(this).attr('value');
if (remove_val != '') {
alert('Not Blank'); // Added for testing
var attr_val = $(product_calendar).attr('value');
if (attr_val.indexOf(remove_val) != -1) {
alert('Eval True'); // Added for testing
var newRemove_val = attr_val.replace(remove_val, '');
$(product_calendar).attr({ 'value': newRemove_val });
$('#calendar_addRemove').fadeOut(500);
}
else {
alert('Eval False'); // Added for testing
$('#calendar_remove').after('<p class="error">Occurrence Not Found</p>');
$('.error').fadeOut(1500, function() { $(this).remove(); });
}
}
else {
alert('Blank'); // Added for testing
$('#calendar_addRemove').fadeOut(500);
}
});
$('input[name=product_calendar]').focus(function() { // Focus on any 'input[name=product_calendar]' executes function
product_calendar = $(this);
$('#calendar_addRemove input').attr({ 'value': '' }); // Clear input fields
$('#calendar_addRemove').fadeIn(500);
});
});

Categories

Resources