combining jquery click functions - javascript

I am quite new to jquery and was wondering if someone could recommend some ways I could combine these functions together so that the code would be more efficient and slimmed down. I basically have two click functions that do the exact same thing but are targeting two different buttons. Thank you.
$( ".step1 button" ).click(function() {
if ($(".step1 input").is(":checked")) {
$( ".step1").slideUp("slow",function(){
$(".step2").slideDown("slow");
});
} // end if
else{
$("div.error").remove();
$(".step1.step-heading").append("<div class='error'><i class='fa fa-exclamation-triangle'></i> Please make a selection before continuing</div>");
} // end else
})// end click function
$( ".step2 button" ).click(function() {
if ($(".step2 input").is(":checked")) {
$( ".step2").slideUp("slow",function(){
$(".step3").slideDown("slow");
});
} // end if
else{
$("div.error").remove();
$(".step2.step-heading").append("<div class='error'><i class='fa fa-exclamation-triangle'></i> Please make a selection before continuing</div>");
} // end else
})// end click function

You can access the DOM element tha trigger the event by using $(this) inside the vent handler.
So, you simply have to attach the same handler to several elements, and use $(this) inside the implementation of the handler.
$(".step1 button").add(".step2 button").click(function() {
// $(this) refered to the button tha triggered the event
}
To make easier to find the step number you can use a custom "data-" attribute, for example like this:
<button data-step-no="1">
You can get that attribute by using $(this).attr('data-step-no'), In fact, to add or substract, you need to parse it like this: var stepno = parseInt($(this).attr('data-step-no').
To select all the buttons wit a single selector you can use buttons like this:
<button data-step-no="1" class="step">
<button data-step-no="2" class="step">
Ans select them all in a single step:
$('button .step').click(...

Here is a simple refactor that will not require changes to HTML:
$('[class^="step"]').each(function(k, v) {
var $btn = $(v).find('button'),
$input = $(v).find('input'),
$next = $(v).next(),
$heading = $(v).find('.step-heading'),
error_html = "<div class='error'><i class='fa fa-exclamation-triangle'></i> Please make a selection before continuing</div>";
$btn.click(function(e) {
if ($input.is(':checked')) {
$(v).slideUp('slow', function() {
$next.slideDown('slow');
});
} else {
$('div.error').remove();
$heading.append(error_html);
}
});
});

Related

How can I combine .toggleClass() with .appendTo()?

I append a new class to a HTML container. How can I toggle this on/off by clicking on the menu button?
And is it even "best practice" to write more complex HTML code in JavaScript or would you prefer another method for this? Because I plan to do this for some more containers. Thank you!
$(document).ready(function() {
$( "a.header-login" ).click(function() {
$("<div class='sub-menu'>" +
"<h2>Hi x!</h2>"+
"<a class='item' href='#'>Logout</a>"+
"</div>")
.appendTo("header .header-r");
})
});
I want to accomplish that another click on "a.header-login" deletes the container ".sub-menu". Now, it is always generated when you click "a.header-login"
In this case you need to add a condition to check whether or not the element already exists. If it doesn't create it, if it does remove it.
jQuery(function() {
$('a.header-login').click(function() {
var $target = $('header .header-r .sub-menu');
if ($target.length === 0) {
$('<div class="sub-menu"><h2>Hi x!</h2><a class="item" href="#">Logout</a></div>').appendTo('header .header-r');
} else {
$target.remove();
}
})
});
That being said, you can make this much simpler logic if you always include the .sub-menu in the HTML of your page but hide it with CSS by default. In that case your jQuery would become a simple call to toggle():
jQuery(function() {
$('a.header-login').click(function() {
$('header .header-r .sub-menu').toggle();
})
});

Combining / Refining two identical blocks of jQuery

I have two blocks of code that function exactly the same but need to fired independently in order to prevent overlap of functionality.
//Block One
jQuery('.top_searchicon').on('click touchstart', (function(e) {
e.preventDefault();
jQuery(this).toggleClass('active');
jQuery('.top_blog_search').toggleClass('active');
}));
//Block Two
jQuery('.searchicon').on('click touchstart', (function(e) {
e.preventDefault();
jQuery(this).toggleClass('active');
jQuery('.blog_search').toggleClass('active');
}));
Thank you very much.
You can combine selectors using a comma (,). You can then use is() and a ternary to choose the relevant element to set the active class on. Try this:
jQuery(function($) {
$('.top_searchicon, .searchicon').on('click touchstart', (function(e) {
e.preventDefault();
var $el = $(this).toggleClass('active');
var targetClass = $el.is('.searchicon') ? '.blog_search' : '.top_blog_search';
$(targetClass).toggleClass('active');
});
});
Note the use of the parameter in the ready handler, this enables you to still use the $ to reference jQuery within the scope of your document.ready handler.
An alternative to using the same event handler and checking within the event handler is to pass parameters to the event handler.
jQuery('.top_searchicon').on('click touchstart', function() {
handleClickTouchStart(".top_blog_search");
});
jQuery('.searchicon').on('click touchstart', function() {
handleClickTouchStart(".blog_search");
});
function handleClickTouchStart(selector)
{
e.preventDefault();
jQuery(this).toggleClass('active');
jQuery(selector).toggleClass('active');
}
This lets you add new handlers without needing to change the handler code (which would become quite messy with more than 2 options using .is (which is ofc fine if you only have 2, maybe 3)), eg:
jQuery('.another_searchicon').on('click touchstart', function() {
handleClickTouchStart(".another_blog_search");
});
The next step would be to use -data attributes to link the two.
This gives you the benefit of being able to add new elements without needing to change any code!
jQuery('.searchhandler').on('click touchstart', function() {
e.preventDefault();
jQuery(this).toggleClass('active');
var other = jQuery(this).data("related");
jQuery(other).toggleClass('active');
});
and change your markup to add matching -data (speculating on the markup here) :
<button type='button' class='searchhandler' data-related='.top_blog_search'>top search</button>
<button type='button' class='searchhandler' data-related='.blog_search'>blog search</button>
<div class='top_blog_search'></div>
...etc
to add another:
<button type='button' class='searchhandler' data-related='.another_search'>another search</button>
<div class='another_search'></div>

Bypass onclick event and after excuting some code resume onclick

I have the below html button which have onclick event
<button onclick="alert('button');" type="button">Button</button>
and the following js:
$('button').on('click', function(){
alert('jquery');
});
After executing some js code by jQuery/Javascript, i want to continue with the button onclick handler e.g: jquery alert first and than button alert.
i tried so many things like "remove attr and append it after executing my code and trigger click (it stuck in loop, we know why :) )" and "off" click. but no luck.
is it possible via jQuery/javascript?
any suggestion much appreciated
Thanks
A little bit tricky. http://jsfiddle.net/tarabyte/t4eAL/
$(function() {
var button = $('#button'),
onclick = button.attr('onclick'); //get onclick value;
onclick = new Function(onclick); //manually convert it to a function (unsafe)
button.attr('onclick', null); //clear onclick
button.click(function() { //bind your own handler
alert('jquery');
onclick.call(this); //call original function
})
});
Though there is a better way to pass params. You can use data attributes.
<button data-param="<%= paramValue %>"...
You can do it this way:
http://jsfiddle.net/8a2FE/
<button type="button" data-jspval="anything">Button</button>
$('button').on('click', function () {
var $this = $(this), //store this so we only need to get it once
dataVal = $this.data('jspval'); //get the value from the data attribute
//this bit will fire from the second click and each additional click
if ($this.hasClass('fired')) {
alert('jquery'+ dataVal);
}
//this will fire on the first click only
else {
alert('button');
$this.addClass('fired'); //this is what will add the class to stop this bit running again
}
});
Create a separate javascript function that contains what you want to do when the button is clicked (i.e. removing the onclick attribute and adding replacement code in its own function).
Then call that function at the end of
$('button').on('click', function(){
alert('jquery');
});
So you'll be left with something like this
function buttonFunction()
{
//Do stuff here
}
$('button').on('click', function()
{
alert('jquery');
buttonFunction();
});
<button type="button">Button</button>

jQuery doesn't recognize a class change

Ok, I have a edit button, when I press on it, it changes to "done" button.
It's all done by jQuery.
$(".icon-pencil").click(function() {
var pencil = $(this);
var row = $(this).parent('td').parent('tr');
row.find('td').not(":nth-last-child(2)").not(":last-child").each(function() {
$(this).html("hi");
});
pencil.attr('class', 'icon-ok-sign');
});
// save item
$(".icon-ok-sign").click(function() {
alert("hey");
});
When I press on a "edit" (".icon-pencil") button, its classes change to .icon-ok-sign (I can see in chrome console),
but when I click on it, no alert shown.
When I create a <span class="icon-ok-sign">press</span> and press on it, a alert displays.
How to solve it?
Try using $( document ).on( "click", ".icon-ok-sign", function() {...
Thats because you can not register click-events for future elements, you have to do it like this:
$(document).on('click', '.icon-ok-sign', function() {
alert('hey');
});
This method provides a means to attach delegated event handlers to the
document element of a page, which simplifies the use of event handlers
when content is dynamically added to a page.
Use following script:
$(document).on('click','.icon-ok-sign',function(){
alert("hey");
});
Try this:
$(".icon-pencil").click(function() {
var pencil = $(this);
var row = $(this).parent('td').parent('tr');
row.find('td').not(":nth-last-child(2)").not(":last-child").each(function() {
$(this).html("hi");
});
pencil.removeAttr('class').addClass('icon-ok-sign');
});
// save item
$(".icon-ok-sign").click(function() {
alert("hey");
});

Is there an easier way to reference the source element for an event?

I'm new to the whole JavaScript and jQuery coding but I'm currently doing this is my HTML:
<a id="tog_table0"
href="javascript:toggle_table('#tog_table0', '#hideable_table0');">show</a>
And then I have some slightly ponderous code to tweak the element:
function toggle_table(button_id, table_id) {
// Find the elements we need
var table = $(table_id);
var button = $(button_id);
// Toggle the table
table.slideToggle("slow", function () {
if ($(this).is(":hidden"))
{
button.text("show");
} else {
button.text("hide");
}
});
}
I'm mainly wondering if there is a neater way to reference the source element rather than having to pass two IDs down to my function?
Use 'this' inside the event. Typically in jQuery this refers to the element that invoked the handler.
Also try and avoid inline script event handlers in tags. it is better to hook those events up in document ready.
NB The code below assumes the element invoking the handler (the link) is inside the table so it can traverse to it using closest. This may not be the case and you may need to use one of the other traversing options depending on your markup.
$(function(){
$('#tog_table0').click( toggle_table )
});
function toggle_table() {
//this refers to the element clicked
var $el = $(this);
// get the table - assuming the element is inside the table
var $table = $el.closest('table');
// Toggle the table
$table.slideToggle("slow", function () {
$el.is(":hidden") ? $el.text("show") : $el.text("hide");
}
}
You can do this:
show
and change your javascript to this:
$('a.tableHider').click(function() {
var table = $(this.name); // this refers to the link which was clicked
var button = $(this);
table.slideToggle("slow", function() {
if ($(this).is(':hidden')) { // this refers to the element being animated
button.html('show');
}
else {
button.html('hide');
}
});
return false;
});
edit: changed script to use the name attribute and added a return false to the click handler.
I'm sure this doesn't answer your question, but there's a nifty plugin for expanding table rows, might be useful to check it out:
http://www.jankoatwarpspeed.com/post/2009/07/20/Expand-table-rows-with-jQuery-jExpand-plugin.aspx

Categories

Resources