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){});
Related
I have a function that is currently using the .getElementBy... DOM calls in JavaScript.
var $ = function (selector) {
var elements = [];
var lastSelector = selector.substring(selector.search(/[^#.]+$/), selector.length);
if(selector.includes('#') !== true || selector.includes('.') !== true) {
elements.push(document.getElementsByTagName(lastSelector));
elements = Array.prototype.slice.call(elements[0]);
}
return elements;
};
There are a number of other if statements in the function using the code:
elements.push(document.getElementsByTagName(lastSelector));
elements = Array.prototype.slice.call(elements[0]);
or
elements.push(document.getElementsByClassName(lastSelector));
elements = Array.prototype.slice.call(elements[0]);
Ideally i'd like to DRY up the repeated:
elements = Array.prototype.slice.call(elements[0]);
but I cannot define it before the if statements because elements has not yet been populated. It therefore tries to run the code on an empty array and errors.
Any suggestions?
Instead of using a home-brew limited function for selecting elements by a selector, you could just use the standard querySelectorAll() available in all browsers including IE8+.
As for converting an array-like object (e. g. a DOM collection) to a real Array (what Array.prototype.slice.call() is used for in your code), I use the following function:
var arrayFrom = function(arrayLike) {
if (Array.from) {
return Array.from(arrayLike);
}
var items;
try {
items = Array.prototype.slice.call(arrayLike, 0);
}
catch(e) {
items = [];
var count = arrayLike.length;
for (var i = 0; i < count; i++) {
items.push(arrayLike[i]);
}
}
return items;
};
or its following simplified version if browsers not supporting passing a non-Array argument to Array.prototype.slice.call() (IE8- if I recall correctly) don’t matter:
var arrayFrom = function(arrayLike) {
return Array.from
? Array.from(arrayLike);
: Array.prototype.slice.call(arrayLike, 0);
};
Certainly consider #marat-tanalin answer. In the case where using querySelectorAll() is not an option, the following worked for me, thanks #master565 for the help:
To start, wrapping the lines:
elements.push(document.getElementsByTagName(lastSelector));
elements = Array.prototype.slice.call(elements[0]);
in a function:
function pushByTag(selector) {
elements.push(document.getElementsByTagName(selector));
elements = Array.prototype.slice.call(elements[0]);
}
Dried things up considerably. Then setting a variable for the if argument helped a lot:
if(selector.includes('#') !== true || selector.includes('.') !== true)
became:
var noClassOrId = selector.includes('#') !== true || selector.includes('.') !== true;
Both these refactors allowed me to single line my if statement in to something I'd argue was fairly readable:
if (noClassOrId) pushByTag(lastSelector);
Sorry for this confusing title.
What i'm trying to do is a function (or just a simple way), which will do simple .next(), but if there's no next element, match first. And the same for .prev() - if there's no previous element, match last.
So i made it this way:
var current_selected = getSelected();
if(current_selected.length) {
var prev = current_selected.prev();
if(prev.length) {
setSelected(prev);
return;
}
}
setSelected(getLast());
But i don't really like it, i think there's some pretty way do it. Any thoughts?
(getSelected and getLast returns jQuery objects.
You could create some little convenience plugins:
$.fn.nextWrap = function() {
var $next = this.next();
if ($next.length) return $next;
return this.siblings().first();
};
$.fn.prevWrap = function() {
var $prev = this.prev();
if ($prev.length) return $prev;
return this.siblings().last();
};
Then you can simply do $('#something').nextWrap() or $('#something').prevWrap().
Here's a quick demo: http://jsfiddle.net/qpDKL/
Note: This will behave mostly like prev() and next() (with the wrap behavior, of course), but it doesn't support the prev|next(selector) syntax.
Edit: Here's a slightly more terse plugin syntax since they're nearly the same anyway:
$.each(['next', 'prev'], function(i, nextOrPrev) {
$.fn[nextOrPrev + 'Wrap'] = function() {
var $item = this[nextOrPrev]();
if ($item.length) return $item;
return this.siblings()[nextOrPrev === 'next' ? 'first' : 'last']();
};
});
This will work for prev case
var current_selected = getSelected();
var prev = current_selected.prev();
if(prev.length) {
setSelected(prev);
} else {
setSelected(getLast());
}
The best way that I can think of would be to have an array of the elements that you want to cycle. You can cycle through an array in two ways:
array.push(array.shift());
or
var count = 0;
function cycle() {
return array[count++ % array.length];
}
I think the former looks cleaner.
http://jsfiddle.net/ExplosionPIlls/feeF5/
Something around these lines:
if (!$('selected').next().length)
return $('selected').parent().children().first();
else
return $('selected').next();
if (!$('selected').prev().length)
return $('selected').parent().children().last();
else
return $('selected').prev();
I needed a method to filter out all elements that are parents of other elements in the result set. I tried to write a plugin:
jQuery.fn.distinctDescendants = function() {
var nodes = [];
var result = this;
jQuery(result).each(function() {
var node = jQuery(this).get(0);
if(jQuery(node).find(result).length == 0) {
nodes.push(node);
}
});
return nodes;
};
When i run the following command on this example page:
jQuery('body, textarea').distinctDescendants();
I get the (wrong) result:
[body.contact-page, textarea, textarea]
This is wrong because body is the parent of at least one other element in the result (both textareas). Therefore the expected result would be:
[textarea, textarea]
What is wrong here?
Why aren't you using jQuery('body > input') instead?
You can use the following (verbose) code to achieve what you want; it should work as drop-in replacement of your plugin code.
jQuery.fn.distinctDescendants = function() {
var nodes = [];
var parents = [];
// First, copy over all matched elements to nodes.
jQuery(this).each(function(index, Element) {
nodes.push(Element);
});
// Then, for each of these nodes, check if it is parent to some element.
for (var i=0; i<nodes.length; i++) {
var node_to_check = nodes[i];
jQuery(this).each(function(index, Element) {
// Skip self comparisons.
if (Element == node_to_check) {
return;
}
// Use .tagName to allow .find() to work properly.
if((jQuery(node_to_check).find(Element.tagName).length > 0)) {
if (parents.indexOf(node_to_check) < 0) {
parents.push(node_to_check);
}
}
});
}
// Finally, construct the result.
var result = [];
for (var i=0; i<nodes.length; i++) {
var node_to_check = nodes[i];
if (parents.indexOf(node_to_check) < 0) {
result.push(node_to_check);
}
}
return result;
};
Your method seems OK but your example is perhaps wrong. You said -
jQuery('body, input').distinctDescendants();
I get the (wrong) result:
[body.contact-page, textarea, textarea]
How come you are getting textarea if that is not there in the selector?
Also be careful using this method. Remember -
jQuery('div, input').distinctDescendants(); means some input are inside the div under consideration and some are outside. Though the result is not unpredictable but it is apparently difficult to guess. So most of the time try use selector having class name or id.
Do let us know your feedback ... I feel the function is ok.
I think this is what you are expecting for
jQuery('body, input').filter(function(){if($(this).children().length >0) return false; else return true; })
or may be rather
jQuery('body, input, textarea').filter(function(){if($(this).children().length >0) return false; else return true; })
and this will return only the text areas(as you want in the example)
jQuery('body, textarea').filter(function(){if($(this).children().length >0) return false; else return true; })
UPDATE
so you want something like this
var elems = 'textarea';
jQuery('body, '+ elems )
.filter(function(){
if($(this).find(elems ).length >0)
return false;
else return true;
})
which returns
[textarea, textarea]
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.
How to count the total number of div elements that are contained in another div using javascript?
The getElementsByTagName() is not only a document method, but one that can run on any DOM element.
element.getElementsByTagName is
similar to
document.getElementsByTagName, except
that its search is restricted to those
elements which are descendants of the
specified element
see more at https://developer.mozilla.org/en/DOM/element.getElementsByTagName
So the actual code that does what you ask is
var container_div = document.getElementById('id_of_container_div');
var count = container_div.getElementsByTagName('div').length;
You can use #davidcmoulton's handy Gist:
https://gist.github.com/davidcmoulton/a76949a5f35375cfbc24
I find it quite useful that it doesn't only count DIVs but also lists the count of all element types of your page.
Here is a copy of the Gist for further reference:
(function (window, undefined) {
// Counts all DOM elements by name & logs resulting object to console.
var forEach = Array.prototype.forEach,
counter = {},
incrementElementCount = function (elementName) {
if (counter.hasOwnProperty(elementName)) {
counter[elementName] += 1;
} else {
counter[elementName] = 1;
}
},
processNode = function (node) {
var currentNode = node;
if (currentNode.nodeType === currentNode.ELEMENT_NODE) {
incrementElementCount(currentNode.nodeName);
if (currentNode.hasChildNodes) {
forEach.call(currentNode.childNodes, function (childNode) {
if (childNode.nodeType === currentNode.ELEMENT_NODE) {
processNode(childNode);
}
});
}
}
};
processNode(window.document.firstElementChild);
console.log(counter);
}(this));
There are many way to count divs element using jquery.
But most popular and simple way are:
$(document).ready(function(){
var divCount = $("div").size();
alert(divCount);
});
AND
$(document).ready(function(){
var divCount = $("div").length;
alert(divCount);
});
Its helpful for you