Best way to traverse dom elements with a condition? - javascript

Which is the best way to find all elements from page which match the size i need, and less browser overloading ?
the most important thing is to make it so that the browser will not overload and will not crash if on page are a lot of elements.
what i'm using now is:
elements = document.getElementsByTagName("*");
len = elements.length;
for(var i = 0; i < len; i++)
if(elements[i].clientHeight == MyHeight && elements[i].clientWidth == MyWidth)
{ /*my code*/ }
Please, if anybody knows a better way which don't stress the browser as much as what I'm using now, then this is what i need.

If you absolutely have to do it, it would be more efficient to iterate through the tree recursively, because then once you hit an element that is less than what you need, you know nothing inside of it can be the required size. Still seems like there would be a better solution under most circumstances, but I don't know your specific problem.
EDIT:
This works.
function findElements( width, height, element ){
var results = Array();
for( var i=0; i<element.childNodes.length; i+=1 ){
var childElement = element.childNodes[i];
if( childElement.clientWidth == width && childElement.clientHeight == height ){
results.push(childElement);
results = results.concat(findElements(width, height, childElement));
} else if( childElement.clientWidth < width || childElement.clientHeight < height ){
continue;
} else {
results = results.concat(findElements(width, height, childElement));
}
}
return results;
}
findElements(myWidth, myHeight, document);

I think we are talking about speed here.(though the difference is marginal).
Who is the fastest??? -->click the run button and test it your self!!!
I guess document.body.querySelectorAll("*"); is a clear winner.
var items = document.body.querySelectorAll("*");
var target, i, len = items.length;
for (i=0;i<len;i++) {
target=items[i];
if(//your condition)
{ and the code}
**Conclusion:**Just write code which are understandable,readable and elegant.I think understanding the logic is the most trivial part.
UPDATE:
function findParentNode() {
var testObj = document.body.querySelectorAll("*");;
for(var i=0;i<=testObj.length;i++){
if(testobj.offsetWidth=="your width" && testobj.offsetHeight=="your height"){
//push it in an array or do whatever you wanted to do
}
else{
//no elements found!!!
}
}
}

Related

Javascript When looping through array, webpage freezes/crashes

So, as the title suggests, when I am looping through a array to do collision in my game, it crashes. Let me give you some more details, when looping through the array, I go through the array once to check collisions for a set object, and use another array to loop through the objects again to do the collision. In a very specific case, the website will crash. When the object collides into a corner and hits both walls, the webpage just stops.
Here is the code for the game:
function RunPhysics()
{
//Move all objects
for(i=0; i<gameObjects.length; i++)
{
var obj = gameObjects[i];
SetObjectPos(obj, obj.xPos + obj.xForce, obj.yPos + obj.yForce);
}
//Check all objects against each other for collision.
var collidedObjects = [];
for(i=0; i<gameObjects.length; i++)
{
var current = gameObjects[i];
for(x=0; x<gameObjects.length; x++)
{
for(z=0; z<collidedObjects.length; z++)
{
--It crashes somewhere around here.
if(collidedObjects[z] == gameObjects[i])
{
break;
}
else
{
continue;
}
}
The objects each contain position, current force, color, and collision type. Any ideas?
So, thanks to someone in the comments, I figured it out. It was a variable that was misbehaving.
The following is the code that I think broke it all.
for(i=0; i<gameObjects.length; i++)
{
var obj = gameObjects[i];
SetObjectPos(obj, obj.xPos + obj.xForce, obj.yPos + obj.yForce);
}
//Check all objects against each other for collision.
var collidedObjects = [];
for(i=0; i<gameObjects.length; i++)
{
Here is the changes that made it work. (Ignore the collidedObjects array being commented out)
for(var i=0; i<gameObjects.length; i++)
{
var obj = gameObjects[i];
SetObjectPos(obj, obj.xPos + obj.xForce, obj.yPos + obj.yForce);
}
//Check all objects against each other for collision.
//var collidedObjects = [];
for(var i=0; i<gameObjects.length; i++)
{
Apparently because of having the same variable being used for two loops, it caused something to break. So I just defined the variables and it worked! Hope this helps someone else who finds this :)

Force begin rendering with javascript

I've an ajax-call that will give me a 500 row return. Each row will create a HTML-object that will be added to the DOM. This all works fine, but it's slow.
I would like to add 20, then render what is done, and then continue to add the last 480. However, I can't figure out how to force rendering.
The code is something like this:
for (i = 0; i < 500; i += 1) {
$(newdata[i]).insertAfter('#object');
}
Where newdata is a textstring, for example
"<p>hello world</p>"
Edit
I might have left out some critical information in my post. The nodes are not to be inserted in order. It's a tree and each node has a parent that I know about. And each parent is garanteed to be inserted before the node. So I can't just append nodes after eachother since they might be in different branches.
Stop inserting one node at the time, insert collections of nodes instead.
It's not the loop that's slow, it's DOM manipulation that is slow, and inserting 500 DOM nodes one node at the time will be slow.
var nodes = $();
for (i = 0; i < 20; i++) {
nodes.append(newdata[i])
}
$('#object').after(nodes);
var more_nodes = $();
for (i = 20; i < 500; i++) {
more_nodes.append(newdata[i])
}
$('#object').after(more_nodes);
If you do it like this, it will probably be ten times faster, and you don't have to insert 20, then 480 etc.
Give the rendering code time to run. Write a few rows, call setInterval() to let other code run, and continue:
function renderLines(newdata) {
var len = newdata.length;
var sofar = 0;
var obj = $('#object');
var renderSome = function() {
for ( var i = 0; (i < 20) && ((i + sofar) < len); ++i )
{
$(newdata[i + sofar]).insertAfter(obj);
}
sofar += 20;
if (sofar < len)
setTimeout(renderSome, 10);
};
setTimeout(renderSome, 10);
}

Javascript: matching a dynamic string against an array

I'm attempting to teach myself javascript. I chose something I assumed was simple, but ran into problems relatively quickly.
I'm attempting to search a string for another string given by the user.
My code so far is:
var source = "XREs2qqAQfjr6NZs6H5wkZdOES5mikexRkOPsj6grQiYNZfFoqXI4Nnc1iONKVrA";
var searchString = []; //the users input
searchString = prompt("Enter search string");
var hits = [];
var one = 0;
var two = 0;
var k = 0;
var sourceSearch = function(text) {
for(i = 0; i < source.length; i++) { //for each character in the source
if(source[i] === searchString[0]) { //if a character in source matches the first element in the users input
one = source.indexOf(i); //confused from here on
for(p = searchString.length; p > 0; p--) {
}
}
}
};
sourceSearch(searchString);
My idea was:
check to see if the first loop finds a character that matches the first character in the user input
if it matches, check to see if the next X characters after the first match the next X characters in the source string
if they all match, push them to the hits array
My problem: I have no idea how to iterate along the arrays without nesting quite a few if statements, and even then, that wouldn't be sufficient, considering I want the program to work with any input.
Any ideas would be helpful. Thanks very much in advance.
Note: There are a few un-used variables from ideas I was testing, but I couldn't make them work.
You can try:
if (source.indexOf(searchString) !== -1) {
// Match!
}
else
{
//No Match!
}
As the other answers so far point out, JavaScript strings have an indexOf function that does what you want. If you want to see how it's done "by hand", you can modify your function like this:
var sourceSearch = function(text) {
var i, j, ok; // always declare your local variables. globals are evil!
// for each start position
for(i = 0; i < source.length; i++) {
ok = true;
// check for a match
for (j = searchString.length - 1; ok && j >= 0; --j) {
ok = source[i + j] === searchString[j];
}
if (ok) {
// searchString found starting at index i in source
}
}
};
This function will find all positions in source at which searchString was found. (Of course, you could break out of the loop on the first success.) The logic is to use the outer loop to advance to each candidate start position in source and use the inner loop to test whether that position actually is the position of a match to searchString.
This is not the best algorithm for searching strings. The built-in algorithm is much faster (both because it is a better algorithm and because it is native code).
to follow your approach, you can just play with 2 indexes:
var sourceSearch = function(text) {
j = 0;
for(i = 0; i < source.length; i++) {
if(source[i] === text[j]) {
j++;
} else {
j = 0;
}
if (j == text.length) {
console.log(i - j); //this prints the starting index of the matching substring
}
}
};
These answers are all pretty good, but I'd probably opt for something like this:
var source = "XREs2qqAQfjr6NZs6H5wkZdOES5mikexRkOPsj6grQiYNZfFoqXI4Nnc1iONKVrA";
var searchString = []; //the users input
searchString = prompt("Enter search string");
var hits = source.split(searchString);
var hitsCount = hits.length - 1;
This way you have all of the data you need to figure out where each hit occurred in he source, if that's important to you.

Get first n text characters of a web page with their styles etc

I want to get the first n characters of a web page and display them as they are displayed in the original document.
I thought of using textContent in JavaScript to get the text, and then somehow recursively get all the DOM (I hope that's the right term) without the text. But it seems that recombining them will be very difficult.
Also, perhaps there's a simple way to achieve this. So why reinvent the wheel?
So how can it be done? (I'm not asking for the whole code, just for an approach to solve this.)
The following code removes all text after the first 35 characters in a document. It ignores non visible text and text nodes that are entirely composed of whitespace. You can see a demonstration of it here:
var limit = 35;
var current = 0;
function recurse(element) {
if (element.childNodes.length > 0) {
for (var i = 0; i < element.childNodes.length; i++) {
recurse(element.childNodes[i]);
}
}
if (element.nodeType == Node.TEXT_NODE && element.nodeValue.trim() != '' && window.getComputedStyle(element.parentElement).height != "auto") {
var length = element.nodeValue.length;
if (current < limit) {
if(current + length > limit){
element.nodeValue = element.nodeValue.substr(0, limit - current)
}
current += length;
} else {
element.nodeValue = "";
}
}
}
var html = document.getElementsByTagName('html')[0];
recurse(html);

For variables in document (Javascript)

This code isn't completely finished yet. I'm trying to iterate over all 'm' variables within a page until there are no more 'm's within the page. Right now I have 'for (m in document)', which I know to be wrong. Can anyone point me in the right direction for the correct syntax?
var m = document.getElementsByClassName('project')
var n = document.getElementsByClassName('web')
var o = document.getElementsByClassName('print')
var p = document.getElementsByClassName('illustration')
function projectFilter(type){
if (type === 'print'){
for (m in document){
if (getElementsByClassName('print') != null){
m.style(opacity=0.3)
console.log("Whatshappening")
}
}
if (type === 'web'){
console.log('webbyshit')
}
if (type === 'illustration'){
console.log('illustrating')
}
if (type === 'project'){
console.log('EVERYTHING')
}
}
Thank you!
You already have m defined at the top of your script, so you don't have to look for it in document. Just loop it like you would loop an array (m is a NodeList object, but it has a length property like arrays do):
for(var i=0; i<m.length; i++) {
// do something with each m[i]
}
Three problems
you are iterating incorrectly
your style assignment is incorrect:
getElementsByClassName will always return an object, even if it is an empty set. Check its length property to see if you get any elements back.
for (var i = 0, len = m.length; i<len; i++) {
if (m[i].getElementsByClassName('print').length > 0 ){
m.style.opacity=0.3;
}
}

Categories