Different/Increasing CSS Value for Many DIVs With Same Class - javascript

I want to use javascript to change the left-margin value of many separate DIVs. The catch is that:
I want to use only one className and
I want the margin to increase, for example, 100px for each instance of the class. This way, instead of having all the DIVs land on top of each other, each DIV will be space out: the first at margin-left:0px, the second at margin-left:100px, the third at margin-left:200px, and so on.
Here is the code that I have which simply applies the same margin-left to all DIVs.
<script>
b = document.getElementsByClassName('spacing');
for (i = 0; i < b.length; i++) {
b[i].style.marginLeft = "100px";
}
</script>
Is there a way to get the javascript to find each instance of the class sequentially and instead of simply applying margin-left:100px to all, it does something like (margin applied to last instance of class + X) so each of 100 DIVs with the same className end up with a unique marginLeft value?

Yes there is a way You can simply multiply the amount of margin by iteration number like this i*100+'px' instead of this "100px"
var b = document.getElementsByClassName('spacing');
for (i = 0; i < b.length; i++) {
b[i].style.marginLeft = i*5+'px';
}
Here is the working example

What you want to do is keeping track of your increasing margin by every iteration of the loop:
b = document.getElementsByClassName('spacing');
var margin = 0;
for (i = 0; i < b.length; i++) {
margin += 100;
b[i].style.marginLeft = margin + "px";
}
That should do the trick.
Check out a working example here: https://jsfiddle.net/c4p9ry46/

Related

Get Z-index of each element on the page

I am trying to find the highest z-index on a page. I am using this
var getStyleProp = function(el, prop){
return window.getComputedStyle(el, null).getPropertyValue(prop);
}
var getHighestZIndex = function(){
var highestZIndex = 0,
HTMLElems = ["a","abbr","acronym","address","applet","area","article","audio","b","base","basefont","bdi","bdo","big","blink","blockquote","body","br","button","canvas","caption","center","cite","code","col","colgroup","content","data","datalist","dd","decorator","del","details","dfn","dialog","dir","div","dl","dt","element","em","embed","fieldset","figcaption","figure","footer","form","frame","frameset","h1, h2, h3, h4, h5, h6","head","header","hgroup","hr","html","i","iframe","img","input","ins","isindex","kbd","keygen","label","legend","li","link","listing","main","map","mark","menu","menuitem","meta","meter","nav","noembed","noscript","object","ol","optgroup","option","output","p","param","plaintext","pre","progress","q","rp","rt","rtc","ruby","s","samp","script","section","select","shadow","small","source","spacer","span","strike","strong","style","sub","summary","sup","table","tbody","td","template","textarea","tfoot","th","thead","time","title","tr","track","tt","u","ul","var","video","wbr","xmp"],
tags,
zIndex;
for (var i = 0; i < HTMLElems.length; i++){
tags = document.getElementsByTagName(HTMLElems[i]);
if (tags){
for (var c = 0; c < tags.length; c++){
zIndex =getStyleProp(tags[c], "z-index");
console.log(tags[c], "zIndex=", zIndex);
if (zIndex > highestZIndex){
highestZIndex = zIndex;
}
}
}
}
return highestZIndex;
}
console.log(getHighestZIndex());
But everything is coming back as "auto". This ancient article explains how a "bug" is causing this behavior. I've tried to make clones of each node, set the position to relative, and then get the z-index,
cl.style.display = "none";
cl.style.position = "absolute";
zIndex = (getStyleProp(cl, "z-index"));
but that is not working either. What is wrong here? Is there a cheaper way to do this than recreating everything on the page?
JSBIN
The node's clone does not seem to get the z-index, while the node itself returns the right value. You could try using it instead (not sure how it might react on a page with lots of content):
var getHighestZIndex = function () {
var highestZIndex = 0,
zIndex,
pos,
tags = document.body.getElementsByTagName('*');
for (var c = 0; c < tags.length; c++) {
// Get the original 'position' property
pos = getComputedStyle(tags[c]).position;
// Set it temporarily to 'relative'
tags[c].style.position = "relative";
// Grab the z-index
zIndex = getComputedStyle(tags[c]).zIndex;
// Reset the 'position'
tags[c].style.position = pos;
console.log(tags[c], "zIndex=", zIndex);
if (zIndex > highestZIndex) { highestZIndex = zIndex; }
}
return highestZIndex;
};
console.log(getHighestZIndex());
JS Fiddle Demo
Changing the element's position temporarily might produce a glitch. You'll need to test that on a page with lots of contents and elements that are position:absolute; or position:fixed;.
If this doesn't fit your use-case, just let me know, and I'll remove it. However, as a thought.
Can you loop through all the tags, and if the value is "auto" assume it's 999. If it's >= 1000, take that as your "highest" value. Then, increment your zIndex up from your highest number that way. This way, the first tag you place will be 1000, the next will be 1001.
var elements = document.getElementsByTagName("*"),
maxZIndex = 999;
for( var i=0; i < elements.length; i++ ) {
var zIndex = parseInt(elements[0].style.zIndex) || 999;
maxZIndex = zIndex > maxZIndex ? zIndex : maxZIndex;
}
return maxZIndex;
This would fit a use case where you are just trying to make sure that the tag you are placing is greater than anything on the page...such as placing a modal.
999 is overkill...somewhat of a "just in case" I missed something because anything with z-index:auto is equivalent to zero. See the following "proof" where even though my z-index is only "1" it overlaps boxes that are 3-deep of "auto".
<div style='position:absolute;background-color:white;z-index:1;width:94px;height:94px;'>
</div>
<div style='position:absolute;background-color:red;width:100px;height:100px;'>
<div style='position:absolute;background-color:blue;width:98px;height:98px;'>
<div style='position:absolute;background-color:green;width:96px;height:96px;'>
</div>
</div>
</div>

In a for loop, how do I increment a counter once every other time?

I apologize for the clunky wording of the question. English is not my first language.
I am creating a scrollable list. Each element of this list consists of a column with two rows. I don't want to offset the column until each row is filled. I basically only want to increment the offset counter every two cycles of the for loop. My code for this is as follows:
var j = 0;
for(var i=0;i<localArray.length;i++){
var iconLeft = 145 * j;
var div = document.createElement('div');
div.id = "page_icon_" + i;
div.style.position = "absolute";
div.style.height = "45px";
div.style.width = "145px";
div.style.left = iconLeft + "px";
var item = fishListItem(localArray[i].info);
div.appendChild(item);
var parent = document.getElementById('tut_icons_scroll');
if(i%2){
item.style.top = "40px";
parent.appendChild(div);
}else{
parent.appendChild(div);
}
if (i%2) {
j++;
}
Is there a way to do with without introducing the variable 'j'?
You could just do:
Math.floor(i/2)
in place of j.
In this case, you can replace all instances of j with Math.floor(i/2).
I would like to use pure css nth-child to accomplish this requirement
if(i%2){
item.style.top = "40px";
parent.appendChild(div);
}
to replace this, in your css div:nth-child(even) { top: 40px; }
to replace j, just create a class for the column, set the margin for it, and position set to relative, float set to left.
can you provide your code in jsbin or jsfiddler so I can help you out. I thought this solution is much clear and easy to maintain.
Would it be easy to use a pass element i and then (i+1) to a function and then count up by 2s?
Something like:
function appendFunction(elementToAdd, addItTo) {}
for (var i = 0; i < localArray.length; i+=2) {
var iconLeft = 145*(i%2); // at 0
var iconRight = 145*(i%2 + 1); // at 145
appendFunction(elementToAdd[i], addItTo}
appendFunction(elementToAdd[i+1], addItTo}
}
Not sure if the function helps a lot, but anyways, adding by twos and treating the cases of (x) and (x+1) within the for loop should allow you to increment a counter once every other time. You have to say what to happen twice each time, but one you make a function for it, it's about as long and leaves you with an easily reusable bit to append the elements in the way to place the text.
You can use Math.floor as stated in a couple of answers. Or bit-shift right by one:
i>>1;
Either substitute j with this expression, or use: var j=i>>1;. i>>1 will have the following values for each loop with an incrementing i:
0,0,1,1,2,2,3,3,4,4,...
Try this:
for(var i=0, j=0; i < 10; i++%2 && ++j) {
console.log(i,j);
}

Reordering and hiding pictures depending on filter and search bar

I'm attempting to create a 'Pick your hero' thing. There are a total of 113 heroes, each are given tags respective to them, for example: wizard, fighter etc.
The way I've done it so far is create a container and add 114 total div's to that container. I have this:
.heroPics {
background-image: url(newHeroes.jpg);
background-size: 792px 792px;
width: 72px;
height: 72px;
float: left;
margin-left: 5px;
margin-top: 20px;
text-align: center;
line-height: 11;
font-size: 15px;
position: relative;
}
for (var i = 1; i < 114; i++) {
srsHeroes[i] = document.createElement("div");
srsHeroes[i].textContent = theNames[i];
srsHeroes[i].className = "championPics " + theNames[i] + "-sprite";
srsHeroes[i].draggable = false;
srsHeroes[i].name = theNames[i];
srsHeroes[i].num = i;
heroSelection.appendChild(srsHeroes[i]);
}
I was thinking of creating an array, for example
wizard = [ 14, 17, 28, 34, 69, 90, 101 ];
and once they click on a checkbox to show only wizard heroes it would do a for loop to hide all 113 divs and then do:
for (var i = 50; i < 70; i++) {
heroSelection.insertBefore(srsHeroes[wizard[i]], srsHeroes[115]);
//and also do style.visiblity = "visible";
}
But it just seems like this is a bad approach to it, or really messy/ugly. I don't really like using library's, including jquery. Is using div's even the right approach? Can anyone with experience give me some advice or links to follow since I must be searching the wrong terms for this.
Also can someone give me some intro on how to create a search bar where they can write hero names and it does the same thing? Reordering and hiding everything properly. Could be cool to have a transition too but not necessary lol. Thanks in advance for reading and all your help.
EDIT: Added my own post since it would have made this too long, let me know what you think
Using classes and jQuery, you can easily match all the divs with that class. If you give all your divs with wizard picts in them a class name of "wizard", then you can select all of them like this:
$("div[class='wizard']").show();
Then to hide the others, you could just do this:
$("div[class!='wizard']").hide();
Also, as you know you can use multiple classes, so you can have a div like this:
<div class="heroPics wizard">
This will first apply the heroPics class styles, then the wizard styles. the latter doesn't have to have anything in it, you can just use it to classify your divs.
for (var i = 1; i < 114; i++) {
srsHeroes[i].style.visibility = "hidden";
}
var test = heroSelection.getElementsByClassName( 'fighter' );
var gg = 1;
var bg = 0;
for (var i = 0, j = test.length; i < j; i++ ) {
test[i].style.visibility = "visible";
test[i].style.transitionDuration= "1.5s";
test[i].style.transitionTimingFunction="ease"
test[i].style.left = -73 + (77 * gg) + "px";
test[i].style.top = -10 + (90 * bg) + "px";
gg ++;
if(gg > 10) {
gg = 1;
bg ++;
}
}
This actually ended up working perfectly. Although I have to reset transitionDuration each time I believe since even to hide divs it would do a 1.5 sec delay if left like that. The insertNode actually fine too, but I couldn't find a way to animate it, here's the code for that if you are interested:
var test = heroSelection.getElementsByClassName( 'wizard' );
for (var i = 0, j = test.length; i < j; i++) {
test[i].style.visibility = "visible";
heroSelection.insertBefore(test[i], heroSelection.firstChild);
the firstChild syntax is awesome, but no animation I ended up switching everything to absolute position, adding a transition duration and just setting the left and top every time.

How to create array and divs with a unique height using jQuery?

I need 100 small divs for my chart, every time I generate them, I they all appear as the same height; the last value from the array.
var valuesG = new Array(100);
for (i = 0; i < valuesG.length; i++ ) {
valuesG[i] = Math.floor(Math.random() * 101);
$("#second").append("<div class='single'></div>");
$(".single").css('height', valuesG[i])
}
Any ideas why this is happening?
You are applying the new height to ALL the .single elements in every iteration. In the last iteration, they end up having the same height.
You could do it like this:
$('<div class="single">')
.css('height', valuesG[i])
.appendTo($('#second'));
Also, your code is not very efficient, take a look at this:
var valuesG = [], //array literal
$elements = $(); //empty jQuery object
for (var i = 0; i < 100; i++) { //we don't have to query array length each iteration
valuesG[i] = Math.floor(Math.random()*101);
//collect the elements into a jQuery object
$elements = $elements.add($('<div class="single">').css('height', valuesG[i]));
}
$elements.appendTo($("#second")); //insert to DOM once - much quicker
jsFiddle Demo
Currently, you're selecting all elements with class single. To get the desired effect, use the appendTo method in the way as shown below.
Side note, the generated heights are not unique, but random. It's possible that two elements exist with, say, height 50. See this question for a method to generate unique random numbers.
var valuesG = new Array(100), i;
for ( i=0; i < valuesG.length; i++ )
{
valuesG[i] = Math.floor(Math.random()*101);
$("<div class='single'></div>")
.css( 'height', valuesG[i] )
.appendTo("#second");
}
You get only one height(last one) because you set same css class in all div and update it's height in every loop so last height value will be applied to all.
As a solution try this:
for ( i=0; i < valuesG.length; i++ ) {
valuesG[i] = Math.floor(Math.random()*101);
$("<div class='single'></div>").css('height',valuesG[i]).appendTo("#second");
}

split html content into fixed height and width divs with jQuery

I'm trying to split a large html page into smaller fixed height and width chunks (pages).
Its pretty easy if I know the pages count - I can generate required number of pages first and then fill them with source content children:
children = $('#source').children();
width = 600;
height = 600;
// already generated 'pages'
divs = $('.page');
$(divs).width(width);
pages = divs.length;
i = 0;
for (var c = 0; c < pages; ++c) {
var div = $(divs).eq(c);
while (i < children.length && div.height() < height) {
$(children[i++]).clone().appendTo(div);
}
if(div.height() > height) {
div.contents().last().remove();
i--;
}
}
But how can I do the same thing if I don't know the pages count?
How to wrap content with $('div.page') and keep adding pages until I reach the end of content?
thanks
You would want to use a loop to keep creating pages / filling them with content until you hit some endpoint, where you'd break out of the loop. The key here is dynamically creating the page divs in the loop. You can use document.createElement or simply $("") (or other jQuery ways). Something like this:
var i = 0;
while(true) {
if (content /* have more content */) {
var page = document.createElement("div");
$(page).addClass('page');
var children = $(content).children();
while (i < children.length && div.height() < height) {
$(children[i++]).clone().appendTo(page);
}
$(body).append(page);
} else {
break;
}
}
You may also want to use jQuery's each method if you have defined blocks of content to add to each 'page'.
Comment if you need more help.

Categories