I am trying to validate multiple fields in a form submit with jQuery, but I cannot get it work. Can someone help me with this?
// Validate checkout fields submit
$( '#checkout-data' ).submit( function( event ) {
$.each( '#checkout-data .required', function(){
if( this.value.length < 1 ) {
$( this ).removeClass( 'valid' ).addClass( 'invalid' );
}
});
event.preventDefault();
});
$( '#checkout-data' ).submit( function( event ) {
$.each( '#checkout-data .required', function(){
if( this.value.length < 1 ) {
$( this ).removeClass( 'valid' ).addClass( 'invalid' );
}
});
if ($('#checkout-data .required.invalid').length) {
event.preventDefault();
alert("invalid");
}
});
Related
I have a task for WordPress website which use Contact Form 7 plugin.
How do I set textarea as required only if value of another field ( [number* number-265 min:0 id:antala] ) > 0 ?
So, it should be not like [textarea* stelnummera id:stelnummera] because this textarea will be required every time.
I have created javascript code which add some classes, attributes and alert message (how it add Contact Form 7 plugin):
$( "#antala" ).change(function() {
if ( $( "#antala" ).val() > 0 ) {
$( "#stelnummera" ).addClass( "wpcf7-validates-as-required wpcf7-not-valid" ).attr( "aria-required", "true" ).attr( "aria-invalid", "true" );
} else {
$( "#stelnummera" ).removeClass( "wpcf7-validates-as-required wpcf7-not-valid" ).attr( "aria-required", "false" ).attr( "aria-invalid", "false" );
}
});
$( ".wpcf7-form" ).submit(function( event ) {
if ( $( "#antala" ).val() > 0 && $( "#stelnummera" ).val() == "" ) {
event.preventDefault();
$( "#stelnummera" ).attr( "aria-invalid", "true" );
$( "#stelnummera" ).after( "<span class='custom-alert' style='color: #f00;'>Dette felt skal udfyldes</span>" );
if ($ ( ".invalid" ).length == 0 ) {
$ ( ".wpcf7-form" ).addClass( "invalid" );
}
} else {
$( "#stelnummera" ).attr( "aria-invalid", "false" );
$( ".custom-alert" ).remove();
}
});
But the form still submitting
I have just hide this textarea until value of number field will be > 0.
Textarea is required [textarea* stelnummera id:stelnummera]
$("#stelnummera").parent().parent().hide();
$("#stelnummera").val('n/a');
$("#antala").change(function() {
if ($("#antala").val() > 0) {
$("#stelnummera").parent().parent().show();
$("#stelnummera").val('');
} else {
$("#stelnummera").parent().parent().hide();
$("#stelnummera").val('n/a');
}
});
I've google for this but I could no find a solution for my issue. I have some events on a js function (Immediate function invocation). Therefore the click event is not working well. It fires only on the second invocation.
The first three fields (To, Cc, and Cco) should expand when you type a long text. The click event should collapse the "To", "Cc" and "Cco" fields when you click on "Subject" field. It works, but only on the second time I click in subject.
Heres my js (IIF)
function initTextareaEvents(){
$('section textarea').on({
focusin:function( ev ) {
if($( this ).closest( '.info-box' ).length > 0){
$( this ).elastic();
}
},
keypress:function( ev ) {
var key = ev.which;
if(key == 13 || key == 32){
ev.preventDefault();
var str = $( this ).val().trim();
str += ', ';
$( this ).val( str );
}
},
click:function ( ev ) {
if($( this ).closest( '.info-box' ).length === 0){
$( '#to, #cc, #cco' ).css( 'height', 'auto' );
}
}
});
}
Here is Codepen
The first click is acting as "Focus Out" I think. try adding something like
focusout:function( ev ) {
if($( this ).closest( '.info-box' ).length > 0){
$( this ).elastic();
}
},
This seems to get you closer to the behavior you want.
On the product category page, when someone clicks "Add to cart", woocommerce adds "View cart" below this button through Ajax. I found that the script which handle this is /assets/js/frontend/add-to-cart.js
Now, I want to add also "Procceed to checkout", so someone can go to checkout immediately.
This is the output of the script:
jQuery( function( $ ) {
// wc_add_to_cart_params is required to continue, ensure the object exists
if ( typeof wc_add_to_cart_params === 'undefined' )
return false;
// Ajax add to cart
$( document ).on( 'click', '.add_to_cart_button', function(e) {
// AJAX add to cart request
var $thisbutton = $( this );
if ( $thisbutton.is( '.product_type_simple' ) ) {
if ( ! $thisbutton.attr( 'data-product_id' ) )
return true;
$thisbutton.removeClass( 'added' );
$thisbutton.addClass( 'loading' );
var data = {
action: 'woocommerce_add_to_cart',
};
$.each( $thisbutton.data(), function( key, value ) {
data[key] = value;
});
// Trigger event
$( 'body' ).trigger( 'adding_to_cart', [ $thisbutton, data ] );
// Ajax action
$.post( wc_add_to_cart_params.ajax_url, data, function( response ) {
if ( ! response )
return;
var this_page = window.location.toString();
this_page = this_page.replace( 'add-to-cart', 'added-to-cart' );
if ( response.error && response.product_url ) {
window.location = response.product_url;
return;
}
// Redirect to cart option
if ( wc_add_to_cart_params.cart_redirect_after_add === 'yes' ) {
window.location = wc_add_to_cart_params.cart_url;
return;
} else {
$thisbutton.removeClass( 'loading' );
fragments = response.fragments;
cart_hash = response.cart_hash;
// Block fragments class
if ( fragments ) {
$.each( fragments, function( key, value ) {
$( key ).addClass( 'updating' );
});
}
// Block widgets and fragments
$( '.shop_table.cart, .updating, .cart_totals' ).fadeTo( '400', '0.6' ).block({
message: null,
overlayCSS: {
opacity: 0.6
}
});
// Changes button classes
$thisbutton.addClass( 'added' );
// View cart text
if ( ! wc_add_to_cart_params.is_cart && $thisbutton.parent().find( '.added_to_cart' ).size() === 0 ) {
$thisbutton.after( ' <a href="' + wc_add_to_cart_params.cart_url + '" class="added_to_cart wc-forward" title="' +
wc_add_to_cart_params.i18n_view_cart + '">' + wc_add_to_cart_params.i18n_view_cart + '</a>' );
}
// Replace fragments
if ( fragments ) {
$.each( fragments, function( key, value ) {
$( key ).replaceWith( value );
});
}
// Unblock
$( '.widget_shopping_cart, .updating' ).stop( true ).css( 'opacity', '1' ).unblock();
// Cart page elements
$( '.shop_table.cart' ).load( this_page + ' .shop_table.cart:eq(0) > *', function() {
$( '.shop_table.cart' ).stop( true ).css( 'opacity', '1' ).unblock();
$( 'body' ).trigger( 'cart_page_refreshed' );
});
$( '.cart_totals' ).load( this_page + ' .cart_totals:eq(0) > *', function() {
$( '.cart_totals' ).stop( true ).css( 'opacity', '1' ).unblock();
});
// Trigger event so themes can refresh other areas
$( 'body' ).trigger( 'added_to_cart', [ fragments, cart_hash, $thisbutton ] );
}
});
return false;
}
return true;
});
Is there anybody who has done something similar?
If you look here from the Woocommerce repo, you can see that add-to-cart.js is localized from that class.
Unfortunately, there isn't a filter to just add your own link. What you could try is copying add-to-cart.js to your theme and set the new src of the registered add-to-cart.js to your new local copy, by using this method.
From there you can alter the this conditional found in Woocommerce repo.
So, technically yes, you could could this, but there are caveats:
You would need to repeat this process for variation products
If translation is a concern, you need to address that as well
Any time the plugin updates, you now have to comb through these files for any differences that could break functionality or cause a security issue.
I have a form that when is submitted it checks if the user selected the field, and if didn't it gives a message to fill, but if i keep clicking the message keeps duplicating, triplicating and goes on... How can i make the message appear only one time? Here is the code
$( "#myform" ).submit(function( event ) {
var met = $("#mySelect").val();
if (met === "0"){
$( ".msn" ).append( "Select a Field" );
return false
}else{
$( "#myform" ).submit();
}
});
Since the problem is on the appended label try this:
$( "#myform" ).submit(function( event ) {
var met = $("#mySelect").val();
if (met === "0"){
// Clear .msn
$(".msn").empty();
// Append label
$( ".msn" ).append( "Select a field" );
return false
}else{
$( "#myform" ).submit();
}
});
Check this updated fiddle.
Use .one function
$( "#myform" ).one('submit', function( event ) {
var met = $("#mySelect").val();
if (met === "0"){
$( ".msn" ).append( "Select a Field" );
return false
}else{
$( "#myform" ).submit();
}
});
I need to write a test for a function that has a setTimeout() call inside, but i can't find how i should do.
This is the function
// Disables all submit buttons after a submit button is pressed.
var block_all_submit_and_ajax = function( el ) {
// Clone the clicked button, we need to know what button has been clicked so that we can react accordingly
var $clone = $( el ).clone();
// Change the type to hidden
$clone.attr( 'type', 'hidden' );
// Put the hidden button in the DOM
$( el ).after( $clone );
// Disable all submit button. I use setTimeout otherwise this doesn't work in chrome.
setTimeout(function() {
$( '#facebook input[type=submit]' ).prop( 'disabled', true );
}, 10);
// unbind all click handler from ajax
$( '#facebook a.btn' ).unbind( "click" );
// Disable all AJAX buttons.
$( '#facebook a.btn' ).click( function( e ) {
e.preventDefault();
e.stopImmediatePropagation();
} );
};
And this is my test
it( "Disable all submit buttons", function() {
// Get a button
var $button = $( '#ai1ec_subscribe_users' );
// Call the function
utility_functions.block_all_submit_and_ajax( $button.get(0) );
// check that all submit are disabled
$( '#facebook input[type=submit]' ).each( function( i, el ) {
console.log( 'f' );
expect( el ).toHaveProp( 'disabled', true );
} );
} );
I've tried using jasmine.Clock.useMock(); and jasmine.Clock.tick(11); but i couldn't get things to work, the test never pass
The overall approach varies based on your Jasmine version.
Jasmine 1.3
You can use waitsFor:
it( "Disable all submit buttons", function() {
// Get a button
var $button = $( '#ai1ec_subscribe_users' );
// Call the function
utility_functions.block_all_submit_and_ajax( $button.get(0) );
// Wait 100ms for all elements to be disabled.
waitsFor('button to be disabled', function(){
var found = true;
// check that all submit are disabled
$( '#facebook input[type=submit]' ).each( function( i, el ) {
if (!el.prop('disabled')) found = false;
});
return found;
}, 100);
});
You could also use waits if you know exactly how long it will take:
it( "Disable all submit buttons", function() {
// Get a button
var $button = $( '#ai1ec_subscribe_users' );
// Call the function
utility_functions.block_all_submit_and_ajax( $button.get(0) );
// Wait 20ms before running 'runs' section.
waits(20);
runs(function(){
// check that all submit are disabled
$( '#facebook input[type=submit]' ).each( function( i, el ) {
expect( el ).toHaveProp( 'disabled', true );
});
});
});
There is also a third way of doing this, without the need for waits, waitsFor, and runs.
it( "Disable all submit buttons", function() {
jasmine.Clock.useMock();
// Get a button
var $button = $( '#ai1ec_subscribe_users' );
// Call the function
utility_functions.block_all_submit_and_ajax( $button.get(0) );
jasmine.Clock.tick(10);
// check that all submit are disabled
$( '#facebook input[type=submit]' ).each( function( i, el ) {
expect( el ).toHaveProp( 'disabled', true );
});
});
Jasmine 2.0
You can use done, the test callback:
it( "Disable all submit buttons", function(done) {
// Get a button
var $button = $( '#ai1ec_subscribe_users' );
utility_functions.block_all_submit_and_ajax( $button.get(0) );
setTimeout(function(){
// check that all submit are disabled
$( '#facebook input[type=submit]' ).each( function( i, el ) {
expect( el ).toHaveProp( 'disabled', true );
});
// Let Jasmine know the test is done.
done();
}, 20);
});
you can mock out the timer behavior:
it( "Disable all submit buttons", function() {
jasmine.clock().install();
// Get a button
var $button = $( '#ai1ec_subscribe_users' );
// Call the function
utility_functions.block_all_submit_and_ajax( $button.get(0) );
jasmine.clock().tick(10);
// check that all submit are disabled
$( '#facebook input[type=submit]' ).each( function( i, el ) {
expect( el ).toHaveProp( 'disabled', true );
});
jasmine.clock().uninstall()
});
For anyone googling this, a better answer can be found timer testing
import { fakeAsync, tick, discardPeriodicTasks } from '#angular/core/testing';
it('polls statusStore.refreshStatus on an interval', fakeAsync(() => {
spyOn(mockStatusStore, 'refreshStatus').and.callThrough();
component.ngOnInit();
expect(mockStatusStore.refreshStatus).not.toHaveBeenCalled();
tick(3001);
expect(mockStatusStore.refreshStatus).toHaveBeenCalled();
tick(3001);
expect(mockStatusStore.refreshStatus).toHaveBeenCalledTimes(2);
discardPeriodicTasks();
}));
Since Jasmine 2 the syntax has changed: http://jasmine.github.io/2.0/introduction.html#section-Asynchronous_Support
You now can simply pass a done callback to beforeEach, it, and afterEach:
it('tests something async', function(done) {
setTimeout(function() {
expect(somethingSlow).toBe(true);
done();
}, 400);
});
Update: Since writing this it's now also possible to use async/await which would be my preferred approach.
I've never done any testing with jasmine, but I think I understand your problem. I would restructure the code a little to allow for you to wrap the function being called in a proxy function like this:
Modify your code that is being test to extract the setTimeout code into another function:
Original Code:
// Disables all submit buttons after a submit button is pressed.
var block_all_submit_and_ajax = function( el ) {
// Clone the clicked button, we need to know what button has been clicked so that we can react accordingly
var $clone = $( el ).clone();
// Change the type to hidden
$clone.attr( 'type', 'hidden' );
// Put the hidden button in the DOM
$( el ).after( $clone );
// Disable all submit button. I use setTimeout otherwise this doesn't work in chrome.
setTimeout(function() {
$( '#facebook input[type=submit]' ).prop( 'disabled', true );
}, 10);
// unbind all click handler from ajax
$( '#facebook a.btn' ).unbind( "click" );
// Disable all AJAX buttons.
$( '#facebook a.btn' ).click( function( e ) {
e.preventDefault();
e.stopImmediatePropagation();
} );
};
Modified Code:
// Disables all submit buttons after a submit button is pressed.
var block_all_submit_and_ajax = function( el ) {
// Clone the clicked button, we need to know what button has been clicked so that we can react accordingly
var $clone = $( el ).clone();
// Change the type to hidden
$clone.attr( 'type', 'hidden' );
// Put the hidden button in the DOM
$( el ).after( $clone );
// Disable all submit button. I use setTimeout otherwise this doesn't work in chrome.
setTimeout(disableSubmitButtons, 10);
// unbind all click handler from ajax
$( '#facebook a.btn' ).unbind( "click" );
// Disable all AJAX buttons.
$( '#facebook a.btn' ).click( function( e ) {
e.preventDefault();
e.stopImmediatePropagation();
} );
};
var utilityFunctions =
{
disableSubmitButtons : function()
{
$( '#facebook input[type=submit]' ).prop( 'disabled', true );
}
}
Next I would modify the testing code like this:
it( "Disable all submit buttons", function() {
// Get a button
var $button = $( '#ai1ec_subscribe_users' );
var originalFunction = utilityFunctions.disableSubmitButtons;
utilityFunctions.disableSubmitButtons = function()
{
// call the original code, and follow it up with the test
originalFunction();
// check that all submit are disabled
$( '#facebook input[type=submit]' ).each( function( i, el ) {
console.log( 'f' );
expect( el ).toHaveProp( 'disabled', true );
});
// set things back the way they were
utilityFunctions.disableSubmitButtons = originalFunction;
}
// Call the function
utility_functions.block_all_submit_and_ajax( $button.get(0) );
});