jquery - returning a value from function - javascript

say I have the following function:
function checkPanes() {
activePane = '';
var panels = $("#slider .box .panel");
panels.each(function() {
//find the one in visible state.
if ($(this).is(":visible")) {
activePane = $(this).index()+1;
console.log(activePane);
}
});
} //END checkPanes();
Ideally, I'd like to call on this function elsewhere (most likely from another function),
and retrieve the value I am currently outputting to console.
(example ..)
function exampleCase() {
checkPanes(); //evidently, does not return anything.
//Ideally, I want the numerical value, being output to console in above function.
}
Thanks in advance! All suggestions / comments are well appreciated.
Cheers

Just noticed the loop; looks like what you may want to return is an array of all active panels (since in theory there could be more than one).
function checkPanes() {
activePanes = [];
var panels = $("#slider .box .panel");
panels.each(function() {
//find the one in visible state.
if ($(this).is(":visible")) {
activePane.push($(this).index()+1);
console.log(activePane);
}
});
return activePanes;
}
If you know there will only ever be one active, you can go back to your original approach and just add return activePane after the console.log.

Forget everyone who says return activePane since they didn't see it's in a jQuery each loop. Won't work.
I'd suggest restructuring your selector. The selector you should be using is: $("#slider .box .panel:visible"). This will cut out your each loop entirely. For instance you could restructure the code as follows:
function checkPanes() {
return $("#slider .box .panel:visible").index();
}
function exampleCase() {
var visiblePane = checkPanes();
// ... do something with the index
}
I'd suggest just using the selector in-line rather than making a new function, but that's a matter of taste, especially if you have to select the same thing in multiple places.

Just switch your console line to a return statement:
function checkPanes() {
activePane = '';
var panels = $("#slider .box .panel");
panels.each(function() {
//find the one in visible state.
if ($(this).is(":visible")) {
activePane = $(this).index()+1;
return activePane; // Return the value and leave the function
}
});
} //END checkPanes();
To call:
function exampleCase() {
var thepane = checkPanes(); //evidently, does not return anything.
// ...
}

I think it's as easy as using return activePane;

This:
function checkPanes() {
activePane = '';
var panels = $("#slider .box .panel");
panels.each(function() {
//find the one in visible state.
if ($(this).is(":visible")) {
activePane = $(this).index()+1;
}
});
return activePane;
} //END checkPanes();
and this:
function exampleCase() {
var myval=checkPanes(); //evidently, does not return anything.
console.log(myval);
}

You can keep your code and just add a return if you want to use the values somewhere else
function checkPanes() {
activePane = '';
var panels = $("#slider .box .panel");
panels.each(function() {
//find the one in visible state.
if ($(this).is(":visible")) {
activePane = $(this).index()+1;
console.log(activePane); //Logs to console.
return activePane; //Returns value also.
}
});
}
So in here you can either use the returned value or just have it log to console. Thats how i understood your question
function exampleCase() {
checkPanes(); //Now it will still write in console. but you dont need to use the return
alert(checkpanes()); //Would write it to console and to an alert!
}
But make sure you return string - or convert to string if you want to disaply it somewhere as text.

you have to return something inside the first function to manipulate it inside the second:
function checkPanes() {
activePane = '';
var panels = $("#slider .box .panel");
//create a return array
visiblePanels = [];
panels.each(function() {
//find the one in visible state.
if ($(this).is(":visible")) {
activePane = $(this).index()+1;
//add the result to the returnb array
visiblePanels[] = activePane
}
});
// return results
return visiblePanels;
}
function exampleCase() {
var thepane = checkPanes();
//now it has all the visible panels that were founded in the other function
// you can access them with thepane[0] or iterate on them
}
I think this is what you need.

Related

Pass dynamic params to IIFE

I've got this issue with passing a variable to an IFFE. did some reading, still didn't figure it out. would really appreciate some guidance here.
i have a click event handler function that gets a certain ID from the
DOM when clicked.
i need to pass that ID to an IIFE
that IFFE needs to either add/remove that ID from an array,
depending if it's already there or not.
This is what I got:
Event:
$(document).on('click', 'input[type="checkbox"]', check);
Click Handler:
function check() {
var id = $(this).closest('ul').attr('data-id');
return id;
}
IIFE:
var checkID = (function (val) {
var arr = [];
return function () {
var i = arr.indexOf(val);
if (i === -1) {
arr.push(val);
} else {
arr.splice(i, 1);
}
return arr;
}
})(id);
right now i'm getting the ID, but returning it to nowhere.
in my IIFE, i did pass an id variable, but it's undefined.
so, how do I pass the ID variable im getting from check() to checkID IIFE?
other solutions are also welcome.
Thanks
In your clickHandler
function check() {
var id = $(this).closest('ul').attr('data-id');
checkID(id);
}
and change checkID to
var checkID = (function () {
var arr = [];
return function (val) {
var i = arr.indexOf(val);
if (i === -1) {
arr.push(val);
} else {
arr.splice(i, 1);
}
return arr;
}
})();
I think you need to do things sort of the other way around. Your check function would return a function used by the event handler, but it would also take a callback to be called after the click handler has run, passing your array.
The check function would look like a mash-up of both your functions:
function check(callback){
var arr = [];
return function(){
var id = $(this).closest('ul').attr('data-id');
var i = arr.indexOf(id);
if (i === -1) {
arr.push(id);
} else {
arr.splice(i, 1);
}
callback(arr);
}
}
As you can see, it takes as a parameter a callback function, which will be called on each execution, passing the current array arr. For example, this is my test callback:
function handler(arr){
alert("Array has " + arr.length + " elements");
}
Finally, your event handler would look like this:
$(document).on('click', 'input[type="checkbox"]', check(handler));
Live example: https://jsfiddle.net/src282d6/
Using getter/setter-like functions in your IIFE function makes it much more organized and readable. Then, use these functions to pass, store, and read data across your IIFE function.
var checkID = (function () {
// your array
var arr = [];
// public
return {
// get
getArray: function(){
return arr;
},
// set value
setArray: function(val) {
var i = arr.indexOf(val);
if (i === -1) {
arr.push(val);
} else {
arr.splice(i, 1);
}
}
}
})();
Use it as follows:
checkID.getArray(); // returns default empty array []
checkID.setArray('car1');
checkID.setArray('car2');
checkID.setArray('car3');
checkID.setArray('car4');
checkID.setArray('car4'); // test splice()
checkID.getArray(); // returns ["car1", "car2", "car3"]

Check whether function has run fully before, based on variable

I have a function which "types" out a header title as though it is being typed on the screen.
The typer only starts typing once a particular section of my site is "active" or is seen on the screen.
At present, it takes the outputID aka the area where this text will be typed into. There are two instances of this function being run, each with different outputIDs - I only want the function to run once per outputID.
This is how the function is initially called.
<h2 id="typer-get-in-touch" class="typer" data-text="Get in Toche^^^^^ Touch"></h2>
if(anchorLink == 'contact'){
var outputID = $("#typer-get-in-touch");
textTyping(outputID);
}else if(anchorLink == 'expertise'){
var outputID = $("#typer-expertise");
textTyping(outputID);
}
This is the textTyping function
function textTyping(outputID){
$(outputID).show();
var textString = $(outputID).data("text");
var textArray = textString.split("");
var texttypeing = setInterval(
function() {
typeOutText(outputID,textArray);
}, 170);
function typeOutText(outputID,textArray) {
if (textArray[0] == "^"){
outputID.text(function(index, text){
return text.replace(/(\s+)?.$/, '');
});
textArray.shift();
}else {
if (textArray.length > 0) {
outputID.append(textArray.shift());
} else {
clearTimeout(texttypeing);
}
}
}
}
My issue at present is that the function runs multiple types, and continues to type each time the original anchorLink trigger is achieved. The result is that is writes the title many times e.g:
Get In TouchGet In TouchGet In Touch
Each time the section is navigated to, the typing starts again.
How can I run this function only ONCE per outputID? So once the outputID has been used, the function can no longer run for that data?
JSFiddle of non-working example: https://jsfiddle.net/qLez8zeq/
JSFiddle of mplungjan's solution: https://jsfiddle.net/qLez8zeq/1/
Change
function textTyping(outputID){
$(outputID).show();
var textString = $(outputID).data("text");
to
function textTyping(outputID){
var textString = $(outputID).data("text");
if (textString=="") return;
$(outputID).data("text","");
$(outputID).show();
FIDDLE
What you need to do is to bind the event handler for each ID and then unbind it after it's been triggered the first time. Since you're already using jQuery, you can use the "one" method to do exactly this for each outputID:
$( "#typer-get-in-touch" ).one( "click", function() {
textTyping(outputID);
});
I suppose you could store your processed outputIds into an array and then check if the given outputId is present in the array before starting?
Define your array, check for the existence, if not found, do code example:
var processedIds = [];
function textTyping(outputID) {
var foundItem = false;
for (var i = 0; i < processedIds.length; i++)
{
if (processedIds[i] == outputID) {
foundItem = true;
break;
}
}
if (!foundItem) {
//the rest of your code goes here
}
}
You can add some check at the beginning of your function:
var called = {};
function textTyping(outputID) {
if (called[outputID]) {
return;
}
called[outputID] = true;
// your code
}

jQuery append issue without removing original elements

I just wrote some code for practicing my jQuery. When I wrote this code, I found out it works fine with only using append() and without removing any original tr elements in the table. How does it work — could someone explain it to me? here is the complete code. Thanks!
Here is my jQuery code:
$(document).ready(function () {
var list = a();
var last = $('#table').find("tr").length;
$('#table').find("tr").each(function (index, element) {
$(this).prepend($("<button/>").text("↑").bind('click', function () {
up($(this).parent(), last);
}));
$(this).prepend($("<button/>").text("↓").bind('click', function () {
down($(this).parent(), last);
}));
});
$('#table').before($('<button />').text("reset").on('click', function () {
reset(list);
}));
});
function up(tr, last) {
if (0 != tr.index()) {
var prevTr = tr.prev();
tr.after(prevTr);
}
}
function down(tr, last) {
if (last - 1 != tr.index()) {
var nextTr = tr.next();
tr.before(nextTr);
}
}
var reset = function (list) {
for (var i = 0; i < list.length; i++) {
$("#table").append(list[i]);
}
};
var a = function () {
var list = [];
$('#table tr').each(function () {
list.push($(this));
});
return list;
};
Be aware, appending already existing element just move it. I guess maybe you want to clone it:
jsFiddle
var reset = function (list) {
for (var i = 0; i < list.length; i++) {
$("#table").append(list[i].clone(true));
}
};
But then, reset function is misnamed...
$(document).ready(function () {
waits for the page and all elements to be loaded
var list = a();
var last = $('#table').find("tr").length;
sets up specific variables, in this case list is the function a() defined later in the page and last gets the length of the last tr in the table.
$('#table').find("tr").each(function (index, element) {
sets up a loop through each tr element on in the table with id #table
$(this).prepend($("<button/>").text("↑").bind('click', function () {
up($(this).parent(), last);
}));
Because you are inside the loop, $(this) represents the tr that the loop is currently on. It then prepends a button and adds a click listener on this button. When the button is pressed, it will call the function up, which is defined later on, with the buttons parent as the first parameter and last (defined earlier) as the second
$(this).prepend($("<button/>").text("↓").bind('click', function () {
down($(this).parent(), last);
}));
This adds another button, but calls down() instead of up()
});
End of the loop.
$('#table').before($('<button />').text("reset").on('click', function () {
reset(list);
}));
This adds a button before the table that when clicked calls the reset function with list as the only parameter, list is set to a().
});
function up(tr, last) {
if (0 != tr.index()) {
var prevTr = tr.prev();
tr.after(prevTr);
}
}
This function is called when moving an item up, it first checks to see if the index is not 0 (so not the first element as this couldn't be moved up) if it is not then it puts the previous tr after the variable tr. Which in this case is the parent to the button (or the current tr)
function down(tr, last) {
if (last - 1 != tr.index()) {
var nextTr = tr.next();
tr.before(nextTr);
}
}
Works exactly the same as the function above, but in the opposite direction.
var reset = function (list) {
for (var i = 0; i < list.length; i++) {
$("#table").append(list[i]);
}
};
This function is saved in the variable reset, it loops through each tr (defined in a()) and appends it to the table,
var a = function () {
var list = [];
$('#table tr').each(function () {
list.push($(this));
});
return list;
};
This function creates and returns an array which loops through each tr and adds to that array. So we know the original state and can return to it.

Use function on all elements in document

I've created a little plugin to check if an element is in position : fixed and to get it's height if it is. What I want is to run this function through all elements in my document to find all fixed elements and get their heights, but I dont know how to write it down
$.fn.isFixed = function () {
if ($(this).css('position') === 'fixed'){
var height = ($(this).height());
return height;
}
else {
return false;
};
}
This is my code.
In that case you may have to return an array since there can be more than one element. Also to make sure that the value indexes are maintained I'm inserting undefined to the array if the position is not fixed
$.fn.isFixed = function () {
var array = [];
this.each(function(){
if ($(this).css('position') === 'fixed') {
array.push($(this).height());
}else{
array.push(undefined);
}
})
return array;
}
var allElements = $("*").contents();
Then use .each() function on allElements variable.
Hope this helps
This search only in declared stylesheets.
var selectorsArray = [];
for (i in document.styleSheets) {
for (k in document.styleSheets[i].cssRules) {
if (document.styleSheets[i].cssRules[k].style.position === "fixed") {
selectorsArray.push(document.styleSheets[i].cssRules[k].selectorText);
}
}
}
So the rest of elements you can select with:
$('[style~=fixed]').each(function(i,e){});

Jquery .each() - return value undefined

Why getColorOptionSelect() return undefined value (I'm sure it has a value by debugger ).
It is for sure an issue related to the scope, sorry for my js ignorance
jQuery(document).ready(function () {
colorSelectID = getColorOptionSelect();
alert(colorSelectID);
function getColorOptionSelect() {
// get label
var selId;
jQuery(".product-options dl label").each(function () {
el = jQuery(this);
// lower case, remove *
var labelText = el.text().toLowerCase().replace("*", "");
if (labelText == 'color') {
//return element
selId = el.parent().next().find("select").attr('id');
return selId;
}
});
// return null;
}
});
getColorOptionSelect doesn't have an (uncommented) return statement.
The only return statement you have is inside the anonymous function you pass to each(). It will be consumed by the code underlying each() (which will stop looping if it is false).
This isn't a problem of scope, just of there being multiple functions.
You probably want to:
define a variable before you call each()
assign a value to it inside the each loop
return that variable at the end of getColorOptionSelect
You should do:
function getColorOptionSelect() {
// get label
var selId;
jQuery(".product-options dl label").each(function () {
el = jQuery(this);
// lower case, remove *
var labelText = el.text().toLowerCase().replace("*", "");
if (labelText == 'color') {
//return element
selId = el.parent().next().find("select").attr('id');
return false; // to stop further execution of each
}
});
return selId;
}
In your case you are doing return from callback function passed to each and it will not be passed from getColorOptionSelect
The only thing you can do returning a value from each function callback is to tell jquery if it should go to next item (return true;) or not (return false;)
Uncomment the last return statement to retun a value (something like selId)
jQuery(document).ready(function () {
colorSelectID = getColorOptionSelect();
alert(colorSelectID);
function getColorOptionSelect() {
// get label
var selId;
jQuery(".product-options dl label").each(function () {
el = jQuery(this);
// lower case, remove *
var labelText = el.text().toLowerCase().replace("*", "");
if (labelText == 'color') {
//return element
selId = el.parent().next().find("select").attr('id');
return false; //<--- return false to stop further propagation of each
}
});
return selId; //<--- Must return something
}
});

Categories

Resources