Passing selectors as function parameters in jQuery [duplicate] - javascript

This question already has answers here:
Calling an event handler with an argument [duplicate]
(5 answers)
Closed 8 years ago.
Fiddle Example
Can I pass selectors other than $(this) selector as function parameters?
What I mean is that the selectors (#Aarea and Barea) I want to pass are the ones that I want to append some HTML content to.
function info(a){
var source = $(this).data('source')
$(a).html(source)
console.log(source);
}
$('#one').click(info('#Aarea'))
$('#two').click(info('#Barea'))
<button data-source="AAA" id='one'>Button</button>
<div id="Aarea"></div>
<div id='Barea'></div>
<a href='#' data-source='BBB' id='two'>Click</a>
But it doesn't work unless I don't use the parameters and specify those selectors in the function.

What your code:
$('#one').click(info('#Aarea'))
...is doing is calling info and passing its return value into click, exactly like foo(bar()) calls bar and passes its return value into foo.
What you want to give click is a function to call. In your case, the simplest way is to use a wrapper function:
$('#one').click(function() {
info(this, '#Aarea');
});
...and update info to accept the element as an argument:
function info(element, a){
var source = $(element).data('source')
$(a).html(source)
console.log(source);
}
Updated Fiddle
Alternately, you can use Function#call to call your original info without changing it:
$('#one').click(function() {
info.call(this, '#Aarea');
});
Function#call calls a function, setting this during the function call to the first argument you give it (and then passing along any other arguments you give to it).
Updated Fiddle

I think your problem is that you're passing the evaluated function into your click handler.
The proper format is something more like this:
$('#one').click(function(){ info('#Aarea'); })
$('#two').click(function(){ info('#Barea'); })
Here's a fiddle with working code -http://jsfiddle.net/2548hkvg/
Alternatively, you could define the target area as a data attribute as well, and only have one function, seen in this fiddle - http://jsfiddle.net/k42ahykb/
In the code for that, we're defining info as our function expression that we pass to the click handler, and this is properly retained.
function info(e){
var source = $(this).data('source');
var target = $(this).data('target');
$(target).html(source)
console.log(source);
}
$('#one').click(info)
$('#two').click(info)

$('#one').click(info('#Aarea'))
You are calling the function here, so the result passed to .click() is undefined. Like #iabw said, you need to wrap it in a function expression so the click event can invoke info() successfully.

Just passthrough this from onclick function to info.
$('#one').click(function(){ info.call(this, '#Aarea'); })
$('#two').click(function(){ info.call(this, '#Barea'); })

Related

jQuery find a class and create callback for its last element

In 'jQuery' I can execute callback for all elements of a class like this way -
jQuery(form_id).find(".multiple_upldprev").each(function () {
But I want to execute only last element of the class. I tried this way -
jQuery(form_id).find(".multiple_upldprev").last(function () {
It doesn't work.
How can I do that?
last() will reduce the set of matched elements to the final one in the set. And it does not take a handler. You can use:
$(...).last().each(function() {
});
Which usually doesn't make sense since .last() just returns the element:
var $lastElement = $(...).last();
// Do something with $lastElement
In cases where you have a predefined handler each might make sense:
$(...).last().each(myHandler);
// The same can roughly be archived with:
myHandler.call($(...).get(-1));
You dont event need a callback.
Since you are interested only in executing a function on last element, You can just do this with a self executing function and the last element in a variable.
(function(){
var $last = jQuery(form_id).find(".multiple_upldprev").last();
// now use this $last
})();
Or for some reason you want to use callback by using each but still execute the callback function only for the last element then you can do this with the help of .is()..
jQuery(form_id).find(".multiple_upldprev").each(function () {
var isLastElement = $(this).is(".multiple_upldprev:last"); //return true only for last element in loop
if(isLastElement ){
//execute your logic for last element
}
});

Hide Collection of jQuery elements in Array Using Hide()/Show()

Seemingly-easy problem here: I'm trying to create a streamlined way to hide/show a collection of DOM elements using some jQuery/vanilla JS. This was from a refactor where several fragmented functions were re-done as better encapsulated versions of their former selves.
What these functions are trying to do take elements from an array (by ID), use map to convert them to jQuery objects, and then hide or show them.
Using jQuery 1.11 in an Angular project, but the angular aspect doesn't seem to interfere with this case, since it won't work in a jsFiddle either.
main problem: When I run the function (usually using a click event), I don't get any sort of error from console and I don't get any sort of result in the DOM either. Any ideas? I'm sure it's a simple thing I'm missing, but I need other eyes on it.
Here's a jsFiddle with the below code loaded in, ready for fixin'. Thanks!
http://jsfiddle.net/sLgqvdku/
function showItem(item) {
return item.show();
}
function hideItem(item) {
return item.hide();
}
function showItemsWithIDs(ids) {
ids.map($).forEach(showItem);
}
function hideItemsWithIDs(ids) {
ids.map($).forEach(hideItem);
}
var itemsHiddenToFocusTribute = ['#form', '#ask', "#submitButton", "#sidebar", "#AmountCtrl", "#giftbutton"];
It appears that only the first element in the array is actually being converted into a jQuery object in your code.
Here's what's happening: vanilla-JS .map passes three arguments to the specified callback function: the current element, the index, and the array.
If the callback function takes only one argument, the second and third are ignored. However, jQuery's $ actually allows two arguments: a selector, and a context (container element). So your code is passing (as the second argument) the array index as a context, resulting in an empty jQuery object -- except for the first element in itemsHiddenToFocusTribute, which has index 0 which is interpreted as no context at all.
You can fix this with an anonymous function that only passes the selector string to $:
function hideItemsWithIDs(ids) {
ids.map(function (i) {
return $(i);
}).forEach(hideItem);
}
http://jsfiddle.net/mblase75/e23qgad5/
However, a more jQuery-friendly way would be to create a single jQuery object of all the desired elements and loop through them using .each:
function hideItem(i,item) {
return $(item).hide();
}
function hideItemsWithIDs(ids) {
$(ids.join()).each(hideItem);
}
http://jsfiddle.net/mblase75/mm2L4xn1/
This is probably more efficient, too, since you're calling $ just once instead of array.length times.
All you're wanting is to send each id through the foreach loop? Then I'd just use each like so:
$(ids).each(function(index, id) {
hideItem(id);
});
You don't need to use map($) to convert them to jQuery objects, just put the object inside the dollar sign function call, like so: $(ids).
Also make sure you pass the actual id to showItem and hideItem when you call them, like so: hideItem(id). You also need to make sure that you use a jQuery object in your hideItem and showItem functions. I changed your code to this:
function showItem(item) {
return $(item).show();
}
function hideItem(item) {
return $(item).hide();
}
function showItemsWithIDs(ids) {
$(ids).each(function(index, id) {
showItem(id);
});
}
function hideItemsWithIDs(ids) {
$(ids).each(function(index, id) {
hideItem(id);
});
}
var itemsHiddenToFocusTribute = ['#form', '#ask', "#submitButton", "#sidebar", "#AmountCtrl", "#giftbutton"];
$('#clicker').click(function(){
hideItemsWithIDs(itemsHiddenToFocusTribute);
});
And here's the updated Fiddle

Using jQuery each() w/ parameter-taking function?

I have a bunch of divs of classname foo within a div of classname fooContainer (these foo divs have been dynamically added to fooContainer).
I have a function operateOnFoo(fooObjectToBeOperatedOn) that operates on a single foo div (that is passed into operateOnFoo as a parameter).
I would like to use the jQuery each() feature to run the operateOnFoo function on all/each of the divs of classname foo within fooContainer. I have tried using calls like:
operateOnFoo( $("#fooContainter").each( ".foo" ) );
and
$("#fooContainter").each( operateOnFoo( foo ) );
and
$("#fooContainer").find(".foo").each( operateOnFoo( ".foo" ) );
but I just can't get it to work. How do I proceed?
I'm a little new to web developing, teaching myself as I go along, so I apologize if this question is overly basic - but I couldn't seem to get it working using other similar Stack Exchange posts as I have been able to do with most of my other issues.
Thanks!
The .each() callback is what it is and you can't change the number of arguments to it or the order in which they appear. So, because your operateOnFoo() function wants different arguments, you can't have .each() call it directly as it is. You can work around it though like this with a stub function that makes the arguments work like you want:
$("#fooContainer .foo").each(function(index, element) {
operateOnFoo(element);
});
Also, the single selector "#fooContainer .foo" will select all items with class="foo" that are contained within the object with id=fooContainer.
If you can change operateOnFoo() to accept the exact two arguments that .each() uses (even if you ignore the first argument), so it was declared like this:
function operateOnFoo(index, element) {...}
then you would be able to just do:
$("#fooContainer .foo").each(operateOnFoo);
each require a function call back ,so give it a function.
$("#fooContainer").find(".foo").each( function(k, div){ operateOnFoo(div) } );
Considering fooContainer to be a class and not the ID of the container. You can use it like so:
$(".fooContainer .foo").each(function(index, element){
operateOnFoo(element);
});
Try this:
$("#fooContainer .foo").each(function(index, element){
//Your code goes here...
alert("Foo index: " + index + "\nContent: " + element);
});
Try this $(".fooContainter .foo").each(function (i, foo) { operateOnFoo( foo )}; );
The $(".fooContainter .foo") will select all the elements with class foo under fooContainer

Need a javascript onclick decorator

I have legacy code that includes links with hard-coded onclick handlers (bad, I know).
link
I need to decorate that onclick function. In other words, I need to to replace the hard-coded onclick function with another function of my own that will first call the original function and then allow me to call my own code.
This is what I've tried, to no avail:
var oldFunc = $('a.linkClass').attr('onclick');
function newFunc(oldFunc) {
return function(oldFunc) {
oldFunc();
// my add'l code
}
}
$('a.linkClass').attr('onclick', '').unbind('click');
$('a.linkClass').click(newFunc(oldFunc));
First issue is need proper selector to find the onclick elements. $('[onclick]') will find all elements in page with that attribute. Also you need to remove the onclick attribute, trying to unbind with jQUery won't work
Assuming each onclick only has one function you could try:
$('[onclick]').each(function(){
var $el=$(this)
var funcName=$el.attr('onclick').replace('()','');
$el.click(window[funcName]).removeAttr('onclick');
});
Just realizing this won't work if any params in function
You are trying to wrap multiple events, but to do that you need to loop over the elements and wrap each one in turn (javascript can't store multiple functions in a single variable like that!) Also you get a string from onclick, so you'll need to eval it (which is generally a BadThing (tm). But the real bad thing here is that you're using onclick in the first place.
var elementsToFix = $('a.linkClass');
for( var i = 0; i < elementsToFix.length; ++ i ) {
var obj = elementsToFix.eq( i );
var oldFnc = obj.attr( 'onclick' );
obj.removeAttr( 'onclick' ).on( 'click', (function( curOldFnc ) {
return function( ) {
// pre-wrapper here
eval( curOldFnc );
// post-wrapper here
}
}( oldFnc )) );
}
This uses the super-evil eval. That's bad, and the only reason I'm using it is because you get a string from attr('onclick') instead of a function. The correct solution is to never use onclick in the first place.
jsfiddle example: http://jsfiddle.net/Jdn6V/1
As the function called from the onclick handler is in the global scope, the easy solution would be to just remove the onclick handler, store the string, and eval it later.
Of course eval is bad, and there are ways to parse the string, remove the parenthesis and keep any arguments, and call it as window[oldFunc] etc. but as a quick example, here it is with eval (which is evil)
$('a.linkClass').each(function() {
var old = $(this).attr('onclick');
$(this).attr('onclick', '').on('click', function(e) {
e.preventDefault();
eval.apply(window, [old]);
alert('new');
});
});
FIDDLE
without eval
$('a.linkClass').each(function() {
var old = $(this).attr('onclick'),
func = old.split('(')[0],
param = old.split('(')[1].replace(')','').split(',');
$(this).attr('onclick', '').on('click', function(e) {
e.preventDefault();
window[func].apply(window, param);
alert('new')
});
});
FIDDLE
.attr() always returns a string, so you'd have to eval it to execute the function.
You can get the original function this way, and not need to eval it later:
var oldFunc = $('a.linkClass')[0].onclick;
([0] picks the "pure" DOM element that has the onclick function.)
Now you can bind the function to the element:
$('a.linkClass').click( function(e) {
// new code here
// ...
oldFunc(e);
});
(e given as the parameter, just in case the old function uses it.)
The additional benefit of this is that it works regardless of what's in the old onclick attribute because it's wrapped in a function, so e.g. onclick="foo(); bar(); return false;" works correctly.

javascript change name of called function

Hi all im very new to javascript so please be gentle.
im mixing php with my calls and I have a slight issue.
I need to alter the function name that is called in an onclick event.
<div class=\"span4\" id=\"pass\">
<button class=\"btn btn-block btn-large btn-warning\" id=\"bypass\" disabled onclick=\"pass(); return false;\">
-
</button>
</div>
above is the div with the std call.
before this point some variables are set from another function call and I need to change the above call to "pinpass2() or pinpass3 etc.
function pincheck(id,type,lastid,pin){
document.getElementById('fade').style.display=\"block\";
document.getElementById('calc').style.display=\"block\";
var staffid = id;
document.getElementById('bypass').onclick = function (){\"pinpass\"+staffid();
return false;
};
}
the above is the function that should do it but i can't seem to get it working.
Any help appreciated.
p.s if i include the following into the pincheck function the desired staffid is diaplayed
alert(\"staff id\"+staffid);
document.getElementById('bypass').onclick = pinpass2;
That should work just fine. pinpass2 is already a function, you can assign it to onclick like any other object (yes, functions are objects in Javascript). So just change the onclick when you need it.
If you can't detect changes to the result of staffid(), then you should use a switch instead.
document.getElementById('bypass').onclick = function() {
switch(staffid()) {
case 1: pinpass(); break;
case 2: pinpass2(); break;
default: pinpass3(); break;
}
};
Though most of the time you don't have to do this. Also, I'm not sure if staffid is supposed to be a function or a variable, but it doesn't change anything.
By the way, this way of attaching handlers is quite old. There's a more powerful one:
document.getElementById('bypass').addEventListener('click', pinpass2, false);
With that you can attach more than one function. To remove one:
document.getElementById('bypass').removeEventListener('click', pinpass2, false);
You can change the onclick attribute the same way you'd change any attribute ?
var elem = document.getElementById('bypass');
elem.setAttribute('onclick', 'pinpass' + staffid + '(); return false;');
FIDDLE
In javascript functions are first class so you can literally just assign pincheck to another variable like this.
var pinpass2 = pincheck;
Now you can still call it like this
pinpass(1,2,3,4);
I'm not 100% from your question, but it looks like you are trying to call a different function based on the staffid variable. I.E. if it is 2 you want to call pinpass2().
If this is a global function you can call window[ 'pinpass' + staffid ]() and it will call the function you want (if it exists).
EXAMPLE: if staffid = 2 then window[ 'pinpass' + staffid ]() is eqivalent to window[ 'pinpass2' ]() which is the same as calling pinpass2().
This works because all global vars (including functions) are properties of the window object, and properties can be accessed using a dynamically generated name and square bracket notation.

Categories

Resources