Refactor same functions with different parent selector jQuery - javascript

I am using two functions that do the same thing but have different parent selectors. Unsure how to combine them into one function?
https://codepen.io/Kerrys7777/pen/gxxLdx
(function($) {
"use strict";
/*---SELECTED ITEM---*/
$(".entity-selectable").click(function() {
if(!$(this).hasClass('selected-item')) {
$('.entity-selectable').removeClass('selected-item');
}
$(this).toggleClass('selected-item');
if ($(this).hasClass("selected-item") && $(".periodicity-selectable").hasClass("selected-item")) {
$("#hidden-content").addClass("fadeInUp");
}
});
/*---SELECTED ITEM---*/
$(".periodicity-selectable").click(function() {
if(!$(this).hasClass('selected-item')) {
$('.periodicity-selectable').removeClass('selected-item');
}
$(this).toggleClass('selected-item');
if ($(this).hasClass("selected-item") && $(".entity-selectable").hasClass("selected-item")) {
$("#hidden-content").addClass("fadeInUp");
}
});
})(jQuery);

you can just make a combined function, and pass it this from click event handler of each class. In the new function just remove class from the siblings of current element. something like this:
(function($) {
"use strict";
function combinedFunction(element){
if(!$(element).hasClass('selected-item')) {
$(element).siblings().removeClass('selected-item');
}
$(element).toggleClass('selected-item');
if ($(".entity-selectable").hasClass("selected-item") && $(".periodicity-selectable").hasClass("selected-item")) {
$("#hidden-content").addClass("fadeInUp");
}
}
/*---SELECTED ITEM---*/
$(".entity-selectable").click(function() {
combinedFunction(this);
});
/*---SELECTED ITEM---*/
$(".periodicity-selectable").click(function() {
combinedFunction(this);
});
})(jQuery);

Probably not the most extensible option, but a quick easy way is the following.
$(".entity-selectable").click(onClick);
$(".periodicity-selectable").click(onClick);
function onClick() {
var className = '';
if ($(this).hasClass('entity-selectable')) {
className = 'entity-selectable';
} else if ($(this).hasClass('periodicity-selectable')) {
className = 'periodicity-selectable';
}
if(!$(this).hasClass('selected-item')) {
$('.'+ className).removeClass('selected-item');
}
$(this).toggleClass('selected-item');
if ($(this).hasClass("selected-item") && $("." + className).hasClass("selected-item")) {
$("#hidden-content").addClass("fadeInUp");
}
}

Related

How to override website_sale_wishlist.js in V11?

I want to override "update_wishlist_view" function which is defined under website_sale_wishlist module. Here is the function:
update_wishlist_view: function() {
if (this.wishlist_product_ids.length > 0) {
$('#my_wish').show();
$('.my_wish_quantity').text(this.wishlist_product_ids.length);
}
else {
$('#my_wish').hide();
}
}
How can i do that?
You could do it like this:
odoo.define('website_sale_wishlist_extension', function (require) {
"use strict";
var ProductWishlist = require('website_sale_wishlist.wishlist');
ProductWishlist.include({
update_wishlist_view: function() {
// execute your code after super call if apply
this._super.apply(this, arguments);
// execute your code before super call if apply
}
});
});

ToggleClass not adding Jquery Delay?

I am trying to add a delay to the toggleclass 'slidein' however it doesn't seem to be adding to it.
here is my fiddle
and here is my code;
$(function () {
$(".expand").on("click", function () {
$(this).next().slideToggle();
if ($(this).next().css("display", "block")) {
$(this).next().children('#slidinghold').delay(5000).toggleClass('slidein');
}
$expand = $(this).find(">:first-child");
if ($expand.text() == "\u25B6") {
$expand.text("\u25BC");
} else {
$expand.text("\u25B6");
}
});
});
Try this:
$(this).next().children('#slidinghold').delay(5000).queue(function(){
$(this).toggleClass("slidein").dequeue();
});
Fiddle
use setTimeout instead of delay. Sample :
$(".expand").on("click", function () {
$(".expand").next().children('#slidinghold').removeClass('active-expand');
$(this).next().children('#slidinghold').addClass('active-expand');
setTimeout(function () {
$('.active-expand').next().children('#slidinghold').toggleClass('slidein');
}, 500);
});
demo https://jsfiddle.net/anthonypagaycarbon/v1geqa8e/
as said by jQuery's doc
.delay() is not a replacement for JavaScript's native setTimeout function, which may be more appropriate for certain use cases
So you can use window.setTimeout to achieve this:
$(function() {
function toggleClassDelay(element,class,delay) {
window.setTimeout(function() {
element.toggleClass(class)
},delay);
}
$(".expand").on("click", function() {
var el;
$(this).next().slideToggle();
if ($(this).next().css("display", "block")) {
el = $(this).next().children('#slidinghold');
toggleClassDelay(el,"slidein",5000)
}
$expand = $(this).find(">:first-child");
if ($expand.text() == "\u25B6") {
$expand.text("\u25BC");
} else {
$expand.text("\u25B6");
}
});
});

jQuery add and remove class checking

This function works. No issues with it working.
if ($(".register-frame").length) {
var emailCheck = /^(([^<>()[\]\\.,;:\s#\"]+(\.[^<>()[\]\\.,;:\s#\"]+)*)|(\".+\"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
$('#email-field').change(function () {
if (!$('#email-field').val().match(emailCheck)) {
if ($("#email-field").hasClass("field-success")) {
$("#email-field").removeClass('field-success');
}
if (!$("#email-field").hasClass("field-error")) {
$("#email-field").addClass('field-error');
}
} else {
if ($("#email-field").hasClass("field-error")) {
$("#email-field").removeClass('field-error');
}
if (!$("#email-field").hasClass("field-success")) {
$("#email-field").addClass('field-success');
}
}
});
}
.login-frame .field-error { border-color: #A94442; }
.login-frame .field-success { border-color: #3C763D; }
Basically this function checks when an email field changes if its a valid email or not. If its not a valid email it removes the valid class if it exists and then adds the invalid class if it doesn't exist.
So my question is, this function seems over done to me. To many checks. Is there a more efficient way of doing the same thing?
I'd simplify it with functions.
In abstract, it would be something like:
$('#email-field').blur(function () {
var is_valid = is_valid($(this).val());
if (is_valid){
$("#email-field").addClass('field-success').removeClass('field-error');
}else{
$("#email-field").removeClass('field-success').addClass('field-error');
}
});
function is_valid(email){
//blah
}
You can simply use addClass and removeClass without checking if the class already exists, since addClass will do nothing if the class is already there, and removeClass will do nothing if the class is not there.
Also, you can use method chaining to make the code shorter.
You can also assign $('#email-field') to a variable so jQuery doesn't have to search for the same element repeatedly.
var $emailField = $('#email-field');
if (!$emailField.val().match(emailCheck)) {
$emailField.removeClass('field-success').addClass('field-error');
} else {
$emailField.removeClass('field-error').addClass('field-success');
}
https://api.jquery.com/toggleClass/
Refer to the toggleClass documentation
You don't need the if statements using hasClass. JQuery will handle that logic for you.
$('#email-field').change(function () {
var cl = ($(this).val().match(emailCheck)) ? 'field-success' : 'field-error';
$(this).removeClass('field-success field-error').addClass(cl)
});
if ($(".register-frame").length) {
var emailCheck = /^(([^<>()[\]\\.,;:\s#\"]+(\.[^<>()[\]\\.,;:\s#\"]+)*)|(\".+\"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
$('#email-field').change(function () {
if (!$('#email-field').val().match(emailCheck)) {
//since it is failure dont check
$("#email-field").removeClass('field-success'); //wont give error if not present
$("#email-field").addClass('field-error');
} else {
$("#email-field").removeClass('field-error');
$("#email-field").addClass('field-success');
}
});
}
.login-frame .field-error { border-color: #A94442; }
.login-frame .field-success { border-color: #3C763D; }
or just simply you can do.
$("#email-field").attr('class','new class') //new class can be either success or error

How to synchronize jquery load files with jquery bind events

I need to add to DOM some html´s by jquery, and bind some events the generated elements, but i cant syncronize it, where the addEvents function starts, the DOM elements are not created, so the $(".login-log") element is not on DOM yet.
I found this:
Javascript Event Synchronization
Im working on it but dont works for me, that my code, i dont know if i miss something or what:
var Login = function ()
{
var commons = new Commons();
this.init = function()
{
stepOne(stepTwo);
commons.init();
}
function stepOne(callback) {
var AsyncDone = function()
{
callback();
}
loadFiles(AsyncDone);
}
function loadFiles(callback)
{
$(".header-container").load("views/header.html");
$(".content-container").load("views/login.html");
callback();
}
function stepTwo() {
addEvents();
}
function addEvents() {
alert("is here");
$(".login-log").bind("click", function() { alert("fuck"); });
}
}
The syncronizathion makes the alert "is here" to appear before the DOM elements of header and login.html are loaded in DOM.
I know that have to be simple, but i dont find the solution.
Thanks in advice.
My final choose:
this.init = function()
{
loadHeader(addHeaderEvents);
loadTemplate(addTemplateEvents);
loadFooter(addFooterEvents);
commons.init();
}
function loadHeader(callback) {
$(".header-container").load("views/header.html", function() {
callback();
});
}
function addHeaderEvents() {
}
function loadTemplate(callback) {
$(".content-container").load("views/template_login.html", function() {
callback();
});
}
function addTemplateEvents() {
alert("llega");
$(".login-log").bind("click", function() { alert("done"); });
}
function loadFooter(callback) {
$(".footer-container").load("views/footer.html", function() {
callback();
});
}
function addFooterEvents() {
}

jQuery, associative array and binding events

I would like to bind the same event to 3 checkboxes but with a different target each time:
var checkboxes = {
'selector1' : 'target1',
'selector2' : 'target2',
'selector3' : 'target3',
};
for (selector in checkboxes) {
var target = checkboxes[selector];
if (jQuery(selector).is(':checked')) {
jQuery(target).show();
}
else {
jQuery(target).hide();
}
jQuery(selector).bind('change', function() {
if ($(this).is(':checked')) {
jQuery(target).show();
}
else {
jQuery(target).hide();
}
});
};
But it doesn't work: on "change", the 3 selectors show/hide the 3rd target.
That's because the code in the event handler will use the variable target, not the value of the variable as it was when the event handler was created. When the event hander runs, the variable will contain the last value used in the loop.
Use an anonymous function to create a closure, that captures the value of the variable:
for (selector in checkboxes) {
var target = checkboxes[selector];
if (jQuery(selector).is(':checked')) {
jQuery(target).show();
} else {
jQuery(target).hide();
}
(function(target){
jQuery(selector).bind('change', function() {
if ($(this).is(':checked')) {
jQuery(target).show();
} else {
jQuery(target).hide();
}
});
})(target);
};
Side note: You can use the toggle method to make the code simpler:
for (selector in checkboxes) {
var target = checkboxes[selector];
jQuery(target).toggle(jQuery(selector).is(':checked'));
(function(target){
jQuery(selector).bind('change', function() {
jQuery(target).toggle($(this).is(':checked'));
});
})(target);
};
It doesn't work because target isn't scoped inside of a function. Blocks DO NOT provide scope in javascript.
But I've reduced it down for you and hopefully this will work out:
$.each(checkboxes, function(selector, target) {
$(selector).change(function () {
$(target).toggle($(selector).is(':checked'));
}).trigger('change');
});
target scope is the problem !
You could have simpler code:
use data for the handler
use .toggle(condition)
$.each(checkboxes, function(selector, target) {
$(selector).on('change', {target:target}, function (evt) {
$(evt.data.target).toggle($(this).is(':checked'));
}).change();
});

Categories

Resources