Simplifying two jQuery functions into one - javascript

Is there one function that would do the job of both of these (and anything that continued the format)?
$("#1A").hover(function(){
$(".route1A").stop().fadeToggle(500);
});
$("#1B").hover(function(){
$(".route1B").stop().fadeToggle(500);
});
The result would look something like below, where __ is code for 'these are the same':
$("#__").hover(function(){
$(".route__").stop().fadeToggle(500);

You can combine the selector for .hover() to include #1A, #1B, etc. and then just grab the id off of the element that triggered the hover event to create your class selector, like so:
$("#1A, #1B").hover(function(){
$(".route" + this.id).stop().fadeToggle(500);
});

Perhaps something like this?
var names = ["1A", "1B"]; //Extend as needed
for(var i=0; i<letters.length; ++i) {
$("#" + names[i]).hover(function() {
$(".route" + names[i]).stop().fadeToggle(500);
});
}

You can use a multi-selector. This will bind the event handler to all selectors included.
$("#1A, #1B").hover(function(){
$(".route" + this.id).stop().fadeToggle(500);
});

Related

Creating multiple event listeners using a loop

Trying to create multiple listeners with a loop. How to make it work?
var buttons = ['one', 'two', 'tree'];
$.each(keys, function(key, value) {
$(value).click(function() {
// do something
});
});
Also, is there a shortcut to not writing key, value when I only need the value?
You are better off putting a delegated event listener on a parent instead of iterating through every button. For example, if you place all your <button> elements inside of a <div> with the id #container, then you can write your listener like this:
$('#container').on('click', 'button', function() {
// do something;
});
Now, every time a button element is clicked within that div, your callback will be invoked. You can also use a class selector in place of 'button' to only listen to elements that have that class.
If you want to make it work by looping then you can use
var buttons = ['.one', '.two', '.three'];
// ---------------- with -------- $.each();
$.each( buttons, function(key, value) {
$(value).click(function() {
// ------------- Do something
});
});
// ------------------ with ----------- for loop
for( var i=0 ; i < buttons.length ; i++ )
{
$(buttons[i]).click(function({
// ------------- Do something
});
}
But why to go this round if just want to assign event
$('.one, .two, .three, #one, #two, #three').click(function() {
// ------------- Do something
});
OR if having variable
var buttons = '.one, .two, .three, #one, #two, #three';
$(buttons).click(function() {
// ------------- Do something
});
AND THATS IT no key, no value, no for, no each
Sounds like you'd be better off assigning the click handler to a button with a specific class name instead of iterating over a list of selectors and assigning a new function inside a loop.
<button class='my-button' id="one">
One
</button>
<button class='my-button' id="two">
Two
</button>
<button class='my-button' id="three">
Three
</button>
and the JS
$('.my-button').click(function() {
var id = $(this).attr('id');
$('body').append("<div>Button " + id + " was clicked</div>");
});
Take a look this fiddle https://jsfiddle.net/4e7rk10L/
In jQuery you can select some elements together, and seperate them using colon ,
var buttons = ['one', 'two', 'tree'];
$(buttons.join()).click(function(){
// Do something
})
In this example I'm using join to convert the array to one,two,three then I add one event listener to all those element
If you really want loop (This was your question) you can do this:
for(var i=0;i<buttons.length;i++)
$(buttons[i]).click(function({
// Do something
})

Where do I put $(this) in the function?

Since I want to use classes instead of id's in these functions(I have three of the same function with different things I want to .append) I am sure I need to put $(this) in those functions somewhere to only trigger only ONE function on button click and not all three of them. but I am not sure because I am a total beginner in jquery/js, so I would appreciate some help.
$(document).ready(function () {
$(".onclick").click(function () {
$('#favorites').append('<div data-role="main"class="ui-content"><div class="ui-grid-b"><div class="ui-block-a">Arrow</div><div class="ui-block-b">More Info</div><div class="ui-block-c">Unfavorite</div></div></div>');
});
});
http://codepen.io/anon/pen/JYxqEw - HTML And the Jquery Code
$('.onclick') selects all the elements with a class of onclick. That means that, whenever something with class="onclick" is clicked, that function will fire.
If you want all of those elements to append that exact HTML to the #favorites element, then you can leave your code as-is.
However, if what you're trying to do is append that html to the clicked element, that is when you'd use $(this) -- that selects the element you clicked with jQuery, then you can append directly to that element ie:
$(document).ready(function () {
$(".onclick").click(function () {
// this will append the HTML to the element that triggered the click event.
$(this).append('<div data-role="main"class="ui-content"><div class="ui-grid-b"><div class="ui-block-a">Arrow</div><div class="ui-block-b">More Info</div><div class="ui-block-c">Unfavorite</div></div></div>');
});
});
EDIT
so to insert the contents of each .onclick into #favorites, you'll need to use the innerHTML value of the DOM node. example fiddle:
http://jsbin.com/qazepubuzu/edit?html,js,output
When you select something with jQuery, you're actually getting back not just the DOM node, but a jQuery object -- this object contains both a reference to the actual DOM node ([0]), as well as a jquery object ([1]).
So to select the DOM node with $(this), you target the node: $(this)[0]. Then you can use .innerHTML() to grab the HTML contents of the node and do as you like.
Final result:
$(function () {
$('.onclick').click(function () {
$('#favorites').append( $(this)[0].innerHTML );
});
});
So the building blocks are not that complex, but I think you're a novice jQuery developer and so you may not be clear on the difference between jQuery and JS yet.
$(selector, context) allows us to create a jQuery collection for a CSS selector which is the child of a current context DOM node, though if you do not specify one there is an automatic one (which is document.body, I think). Various functions iterating over jQuery collections make the particular element available as this within the JavaScript. To get to the strong element from the .onclick element in the HTML fragment you need to travel up in the hierarchy, then to the appropriate element. Then, we can collect the text from the element. We can do this in either JS or jQuery.
To do this with simply jQuery:
// AP style title case, because Chicago is too crazy.
var to_title_case = (function () { // variable scope bracket
var lower_case = /\b(?:a|an|the|and|for|in|so|nor|to|at|of|up|but|on|yet|by|or)\b/i,
first_word = /^(\W*)(\w*)/,
last_word = /(\w*)(\W*)$/;
function capitalize(word) {
return word.slice(0, 1).toUpperCase() + word.slice(1).toLowerCase();
}
function capitalize_mid(word) {
return lower_case.exec(word) ? word.toLowerCase() : capitalize(word);
}
return function to_title_case(str) {
var prefix = first_word.exec(str),
str_minus_prefix = str.slice(prefix[0].length),
suffix = last_word.exec(str_minus_prefix),
center = str_minus_prefix.slice(0, -suffix[0].length);
return prefix[1] + capitalize(prefix[2]) + center.replace(/\w+/g, capitalize_mid)
+ capitalize(suffix[1]) + suffix[2];
};
})();
$(document).ready(function() {
$(".onclick").click(function () {
var text = $(this).parents('.ui-grid-a').find('.ui-block-a').text();
var html = '<div data-role="main"class="ui-content">'
+ '<div class="ui-grid-b"><div class="ui-block-a">'
+ to_title_case(text) + '</div><div class="ui-block-b">More Info</div>'
+ '<div class="ui-block-c">Unfavorite</div></div></div>';
$("#favorites").append(html);
});
});

How to retrieve id from selected item using "this"

I am new at jQuery/javascript. I tried some suggestions I found on this forum but so far it did not help.
THis is what I am trying:
When loading categories from a database ( using ajax) this HTML statement is added for each category:
$("#Links ul").append('<li id=\"cat' + i + '" data-catid=' + i + '>' + categorie_tekst[1] + '</li>');
Using F12 I see that the lines are correctly added.
E.g. <li id="cat3" data-catid="3">Seafood </li>
Next step is selecting a category in the screen and retrieve the products of this category using the value set for data-catid.
I have been told that I could "this.id" but so far no luck. Displaying the value of this.id with alert returns the correct value but for some reason I can't use it.
When I add (#cat3).attr(“data-catid”) in the code it works. But different options like these did not work:
("#cat"+ this.id).attr(“data-catid”)
(this).attr(“data-catid”)
var x = $(this).id();
var rest = x.substr(4, 1);
Everything with "this" creates error : Uncaught TypeError: ("#cat" + this.id).attr is not a function...
Trying to display any of these options does not give any output (not even a popup when I set an alert)
Any help would be appreciated!
You are loading dynamic values. Please use Event Delegation. And the $.one() binds the event once.
You need to add this in your ready function.
$(document).ready(function () {
$("#Links ul").one("click", ".cat", function(){
alert($(this).data('catid'))
});
});
To get the IDs of the elements, use $(this).attr("id") or $(this).prop("id") (latest jQuery) instead of this.id, as sometimes, it might return the jQuery object.
As you are creating elements like
$("#Links ul").append('<li class="cat" id=\"cat' + i + '" data-catid=' + i + '>' + categorie_tekst[1] + '</li>');
create elements using jQuery
$("#Links ul").append( $('<li></li>', {
class: "cat",
id: "cat" + i,
data-catid: i,
text: categorie_tekst[1]
});
As you are creating elements dynamically use Event Delegation. You have to use .on() using delegated-events approach.
$(document).ready(function () {
$("#Links ul").on(event, ".cat", function(){
alert($(this).data('catid'))
});
});

How to simplify code to add new elements to a page with jQuery?

I've written the following code to add a clickable "link button" to a section of my page.
var linkButtonHtml = "<a data-makeId='" + makeId + "' href='javascript:expandMake(" + makeId + "," + categoryId + ")'>+</a> " + makeName;
var divHtml = "<div style='display:none' class='models' data-makeId='" + makeId + "'></div>" + "<br/>";
html += linkButtonHtml + divHtml;
$('#linkDiv').html(html);
The code works fine, but it's ugly and difficult to read with all the string concatenation.
As you can see, I am building anchor elements and div elements with string concatenation. The target of my anchor element is a javascript function invocation with two arguments. Is there a good jQuery way to improve the readability of this code?
I'm not sure if this really improves readability is here is a 100% jQuery solutions:
$(html)
.append(
$('<a />')
.attr('data-makeId', makeId)
.attr('href', 'javascript:void(0);')
.click(function(event)
{
// Prevent clicking the link from leaving the page.
event.preventDefault();
expandMake(makeId, categoryId);
})
.text('+'))
.append(
document.createTextNode(makeName)
)
.append(
$('<div />')
.addClass('models')
.attr('data-makeId=', makeId)
.hide());
Where "html" in $(html) is the html variable you have in your sample.
jQuery offers an option for a second argument when creating elements.
var linkButton = $('<a>',{'data-makeId':makeId,
href:'#',
click:function(){expandMake( makeId, categoryId )},
text:'+'
});
var div = $('<div>',{ style:'display:none',
'class':'models',
'data-makeId': makeId
})
.after('<br>');
$('#linkDiv')
.empty()
.append(html)
.append(linkButton)
.append( makeName )
.append(div);
EDIT: Fixed an issue where makeName was not appended.
Only real way is either abstracting some of your tag generation or spread the script out a little to make it more readable : http://jsfiddle.net/3dYPX/1/
Your also using jQuery so you might want to consider changing the way you trigger the javascript. Try looking into the .live() event. (Ill just get an example up, not that its very important)
Using live event for unobtrusive javascript:
http://jsfiddle.net/3dYPX/2/
It is all being done inside of the onLoad event at the moment, just to use as an example.
Use a template library such as
jQuery Templates instead of inlining
HTML.
Instead of using "javascript:" URLs, attach event handlers to the generated DOM fragments.
Refrain from using inline styles.
Something like:
$('#linkDiv')
.empty()
.append($.tmpl(myTemplate, {
makeId: makeId,
makeName: makeName,
categoryId: categoryId
}))
.click(function () {
var makeId = $(this).attr("data-makeId");
if (makeId) {
expandMake(makeId, $(this).attr("data-categoryId"));
}
});
Where myTemplate has the content:
${makeName}
<div class="models" data-makeId="${makeId}"></div>
Instead of using an inline style to initially hide the models, hide them all with a general CSS rule, and then selectively show them with a class:
.models { display: none }
.models.shown { display: block }
Just add the "shown" class to show a certain block of models.
Here you go:
$('#linkDiv').empty().append([
$('+').data('makeId', makeId).click(function(e) {
e.preventDefault();
expandMake(makeId, categoryId);
})[0],
$('<span>').text(makeName)[0],
$('<div class="models">').data('makeId', makeId).hide()[0],
$('<br>')[0]
]);
Live demo: http://jsfiddle.net/cncbm/1/
Consider this:
$('#linkDiv').data({'makeId': makeId, 'categoryId': categoryId}).empty().append([
$('+').click(expandMake)[0],
$('<span>').text(makeName)[0],
$('<div class="models">').hide()[0]
]);
So, you define that data-stuff on the parent DIV (the common parent) and you re-factor the expandMake function so that it reads those data-values from the parent DIV instead of passing them as arguments.

jQuery Closures, Loops and Events

I have a question similar to the one here: Event handlers inside a Javascript loop - need a closure? but I'm using jQuery and the solution given seems to fire the event when it's bound rather than on click.
Here's my code:
for(var i in DisplayGlobals.Indicators)
{
var div = d.createElement("div");
div.style.width = "100%";
td.appendChild(div);
for(var j = 0;j<3;j++)
{
var test = j;
if(DisplayGlobals.Indicators[i][j].length > 0)
{
var img = d.createElement("img");
jQuery(img).attr({
src : DisplayGlobals.Indicators[i][j],
alt : i,
className: "IndicatorImage"
}).click(
function(indGroup,indValue){
jQuery(".IndicatorImage").removeClass("active");
_this.Indicator.TrueImage = DisplayGlobals.Indicators[indGroup][indValue];
_this.Indicator.FalseImage = DisplayGlobals.IndicatorsSpecial["BlankSmall"];
jQuery(this).addClass("active");
}(i,j)
);
div.appendChild(img);
}
}
}
I've tried a couple of different ways without success...
The original problem was that _this.Indicator.TrueImage was always the last value because I was using the loop counters rather than parameters to choose the right image.
You're missing a function. The .click function needs a function as a parameter so you need to do this:
.click(
function(indGroup,indValue)
{
return function()
{
jQuery(".IndicatorImage").removeClass("active");
_this.Indicator.TrueImage = DisplayGlobals.Indicators[indGroup][indValue];
_this.Indicator.FalseImage = DisplayGlobals.IndicatorsSpecial["BlankSmall"];
jQuery(this).addClass("active");
}
}(i,j);
);
Solution by Greg is still valid, but you can do it without creating additional closure now, by utilizing eventData parameter of jQuery click method (or bind or any other event-binding method, for that matter).
.click({indGroup: i, indValue : j}, function(event) {
alert(event.data.indGroup);
alert(event.data.indValue);
...
});
Looks much simpler and probably more efficient (one less closure per iteration).
Documentation for bind method has description and some examples on event data.
Nikita's answer works fine as long as you are using jQuery 1.4.3 and later. For versions previous to this (back to 1.0) you will have to use bind as follows:
.bind('click', {indGroup: i, indValue : j}, function(event) {
alert(event.data.indGroup);
alert(event.data.indValue);
...
});
Hope this helps anyone else still using 1.4.2 (like me)

Categories

Resources