How to get the maximum Z-Index of multiple elements (JQuery) - javascript

I am currently working on a bug and do not seem to find a solution that satisfies my senior dev. I have the following problem:
I have a dashboard where the user can drag and drop multiple elements into it and set them the way he wants. Now, whenever a new element is dragged into the dashboard, its z-index gets set to 'auto' and it appears behind the other elements. I want to get the highest z-index available on the dashboard.
I already have written a function that gets me the highest z-index just fine, as you can see below.
function getZIndexOfElementAndAddOne() {
let temp = -1;
$('.elementIwant').each(function() {
let zIndex = $(this).css('z-index');
while (temp <= zIndex) {
temp++;
}
However, my senior dev tells me that it consumes to many resources and that I should swap the while loop with an if statement like so.
function getZIndexOfElementAndAddOne() {
let temp = -1;
$('.elementIwant').each(function() {
let zIndex = $(this).css('z-index');
if (temp <= zIndex) {
temp++;
}
But if I actually do that, the function does not return me the z-indexes of the elements but instead something else I don't even know what it is.
I would be really glad if someone could help me with this. Even an advice on how to approach the problem another way is more than welcomed

function getZIndexOfElementAndAddOne() {
const newElement = document.querySelectorAll(".newElement")[0];
const aElements = document.querySelectorAll(".elementIwant");
let temp = -1;
aElements.forEach(el => {
let zIndex = parseInt(el.style.zIndex);
if (temp <= zIndex) temp = zIndex + 1;
});
newElement.style.zIndex = temp;
console.log("Z-Index new element: " + newElement.style.zIndex);
}
getZIndexOfElementAndAddOne();
<div class="newElement"></div>
<div class="elementIwant" style="z-index: 1;"></div>
<div class="elementIwant" style="z-index: 2;"></div>
<div class="elementIwant" style="z-index: 100;"></div>
<div class="elementIwant" style="z-index: 50;"></div>

Without doing an iteration loop, I think you can combine both CSS and JS. Here's what I would attempt to solve your ticket.
The idea is, whenever a new element is being added / dragged or whatever, you should have something UNIQUE to specific it. I'd suggest adding a CSS class like current-item or something like that to the element.
Once the element is added into the DOM tree, CSS will shine with this simple selector:
.whatever .item.current-item {
z-index: 99999 !important;
}
Notice that this approach utilizes the !important flag that most jQuery or js lib use to override the styling of a DOM element. Here we're using it to make sure it will be the highest element, of course, when there's no item being dragged/added, the CSS won't apply.
You can even easily toggle the state of any DOM with something like $('.item').toggleClass('current-item') in jQuery.
I hope this approach would satisfy your "Senior Dev", the mindset behind this is based on the state of an item, and the DOM will reflect this state, the same like React guys do.
Update:
- My suggestion is to try your best to inspect the "new element", if it already has its unique CSS class, then re-use this class. Otherwise, try to add a specific class for this "new element" and proceed

Related

how to fix this function so it keeps detecting clicks?

This is my first question please go easy on me.
The issue I am having is I have a for each PHP loop to map out (populate) the divs based on how many customer profiles are in the database.
each div has the same class name, so... I use querySelectorAll('.customerBox') to create a NodeList with x amount of divs based on rows in the database.
With this, I am able to change styles based on the index of each item.
Below is a quick example of the script i'm running to do this:
for (let i = 0; i < customerBox1.length; i++) {
(function(e){
openCustBoxBtn1[e].onclick = function(){
if(customerBox1[e].style.minWidth == '100%'){
custCreationBox.style.display = 'flex';
customerBox1[e].style.minWidth = '25%';
customerBox1[e].style.minHeight = '50%';
}
if(customerBox1[e].style.minWidth < '100%'){
custCreationBox.style.display = 'none';
customerBox1[e].style.minWidth = '100%';
customerBox1[e].style.minHeight = '100%';
}
}
})(i);
}
This works perfectly fine the only issue is that the function only runs for two clicks on any element, so let's say there are three elements (.customerBox1)'s... I can click the button within the box to make it take up the 'full screen' then if I click that button again and element (.customerBox1) at the index of whichever you clicked has a minWidth of 100% it will shrink back to its original size, BUT after this that individual elements cannot be re-opened, but any other element at another index can.
gonna be honest I have a vague understanding of how this function works I found it here on stack overflow when searching how to run an onClick for querySelectorAll() at the index of the element you clicked.
Anything helps thank you, if you need more information please let me know. I tried to describe my issue as in-depth as possible.
First of all this condition
customerBox1[e].style.minWidth < '100%'
It will not work as expected as you compare strings, you need map the value of minWidth to a number with parseInt(customerBox1[e].style.minWidth)
ex:
const minWidth = parseInt(customerBox1[e].style.minWidth)
if(minWidth === 100){
// code ...
}
if(minWidth < 100){
// code ...
}

Javascript/Tumblr: add CSS class on condition (has to be JS because Tumblr)

I'm very sorry but after a few hours of trying I just have to ask the experts :)
I've got the following code in my Tumblr theme:
{block:Photo}
<li class="post photo">
// Retrieving photo url here using {PhotoURL-500}.
{/block:Photo}
This retrieves all photo posts and displays them on a page.
Now I want to give the li a class, depending on the image orientation. I've retrieved this by using:
<script type="text/javascript">
var width = {PhotoWidth-500}; // this is a Tumblr variable that gets the width
var height = {PhotoHeight-500}; // this is a Tumblr variable that gets the height
if (width > height) {
// Here I get stuck, I want to append class="horizontal" to the li above.
}
else {
// append class="vertical"
}
</script>
I do have to call the javascript inside the {block:Photo} though, as otherwise I cannot determine each photo's individual height and width. And as a reminder; I'd love to do this in PHP and just echo it, but Tumblr does not allow that. And I'm a JS noob...
Help would be much appreciated! Thanks in advance!
On any modern browser, you can use querySelectorAll to get a NodeList of elements matching a selector, e.g.
var list = querySelectorAll(".post.photo");
...and then loop through them appending to their className property. E.g.:
var list = querySelectorAll(".post.photo"),
index,
node;
for (index = 0; index < list.length; ++index) {
node = list[index];
if (some_condition) {
node.className += " theNewClassToAdd";
}
}
If you need to support older browsers, getElementsByClassName has been around for a long time (but I believe it only supports querying by a single class, so you'd have to post-process to make sure both classes existed).
Or for broadest support, leverage the work of others by using a decent library like jQuery, YUI, Closure, or any of several others.

Changing the "x" in background-position: "x"px "y"px using jQuery/Javascript for a class

I've just started using sprites to cut down HTTP requests and I'm having a little bit of a problem converting my old script for dealing with my hover animations into the new system. I don't really want to be having a separate function for each button as that is painful especially with the amount of buttons, even copy and paste would be a pain. I don't believe it's the most efficient way of doing things either, not by a long shot and efficiency is the aim here.
I have gotten this far with it:
$(".socButton").hover(function(){
var iD = $(this).attr("id");
var pos = $("#" + iD).css("background-position");
var splitPos = pos.split("px");
splitPos[0] = parseInt(splitPos[0]) += 24;
newPos = splitPos.join("px");
alert(newPos);
}, function(){
});
but the newPos variable just isn't alerting. I've tried some easier looking methods of just changing "background-position-x" but no dice there.
I'm not certain I need to identify the id of the element in order to change it, but it is the id which has the background-position in the stylesheet, not the class, so I'm not really certain.
Any guidance greatly appreciate.
Thanks in advance.
EDIT: I feel I should also point out, it was alerting fine before I added the parseInt, but some whacky results were coming about before I added it.
No, you don't need the ID of the element. jQuery applies inline styles.
Anyway, it would probably be easier if you had a second rule for .socButton in your CSS, i.e. .socButton.hover, which would have correct background position for hover state. In jQuery you would only have to toggle the hover class with $(this).toggleClass('hover').
http://jsfiddle.net/Rn6f4/
$(".socButton").hover(function() {
var pos = $(this).css("background-position");
var splitPos = pos.split("px");
splitPos[0] = parseInt(splitPos[0]);
splitPos[0] += 24.0;
newPos = splitPos.join("px");
alert(newPos);
$(this).css({"background-position": newPos});
}, function(){
});

While loop in jquery of dynamic id and class

I have have multiple divs' with similar code within it, but also has a unique id within the main div that calls a toggleClass & slideToggle function. I'm trying to create a loop so that I do not have to write similar code for each element.
--- working code --- (where numeric value after the id would change)
$('#er1').click(function() {
$('#er1').toggleClass('but-extra-on');
$('#cr1').toggleClass('but-closerow-on');
$('#er1').next('div').slideToggle('slow');
return false;
});
-- not working code -- (I want to have functions for the click of #er1, #er2, #er3 etc.)
var count = 1;
while (count < 10){
var curER = 'er'+count;
var curCR = 'cr'+count;
$('#'+curER).click(function() {
$('#'+curER).toggleClass('but-extra-on');
$('#'+curCR).toggleClass('but-closerow-on');
$('#'+curER).next('div').slideToggle('slow');
});
count++;
}
* for some reason, when I use the while code, whenever I click #er1, #er2, #er3 etc.. only the event for #er9 toggles.
You can solve this problem, by using the $(this) selector for the one that you are clicking, and attaching an html data attribute to the div, specifying the other div that you want to change when you click it and selecting the other one with that... make sense.. probably not? Check out Solution 1 below.
The second solution is to use jQuery Event Data to pass the count variable into the event listener.
Solution 1: http://jsfiddle.net/Es4QW/8/ (this bloats your html a bit)
Solution 2: http://jsfiddle.net/CoryDanielson/Es4QW/23/
I believe the second solution is slightly more efficient, because you have slightly less HTML code, and the $(this) object is slightly smaller. Creating the map and passing it as event data, I believe, is less intensive... but... realistically... there's no difference... the second solution has cleaner HTML code, so you should use that.
Solution 3 w/ .slideToggle(): http://jsfiddle.net/CoryDanielson/Es4QW/24/
Edit: Updated solutions by passing in the selected elements instead of the selectors. Now each click event will not do a DOM lookup as it did before.
I've run into this problem before. I fixed it by extracting the event listener code into its own function like so:
for (var i = 1; i < 10; i++) {
attachClickEvent('er'+i, 'cr'+i);
)
function attachClickEvent(cr, er)
{
$('#'+er).click(function() {
$(this).toggleClass('but-extra-on');
$('#'+cr).toggleClass('but-closerow-on');
$(this).next('div').slideToggle('slow');
});
}

How can I undo the setting of element.style properties?

I have an element in my document that has a background color and image set through a regular CSS rule.
When a certain event happens, I want to animate that item, highlighting it (I'm using Scriptaculous, but this question applies to any framework that'll do the same).
new Effect.Highlight(elHighlight, { startcolor: '#ffff99', endcolor: '#ffffff', afterFinish: fnEndOfFadeOut });
The problem i'm facing is that after the animation is done, the element is left with the following style (according to FireBug):
element.style {
background-color:transparent;
background-image:none;
}
Which overrides the CSS rule, since it's set at the element level, so I'm losing the background that the item used to have...
What I'm trying to do is, in the callback function I'm running after the animation is done, set the style properties to a value that'll make them "go away".
var fnEndOfFadeOut = function() {
elHighlight.style.backgroundColor = "xxxxx";
elHighlight.style.backgroundImage = "xxxxx";
}
What I'm trying to figure out is what to put in "xxxx" (or how to do the same thing in a different way).
I tried 'auto', 'inherit', and '' (blank string), and neither worked (I didn't really expect them to work, but I'm clueless here).
I also tried elHighlight.style = ""; which, expectably, threw an exception.
What can I do to overcome this?
I know I can put a span inside the element that I'm highlighting and highlight that span instead, but I'm hoping I'll be able to avoid the extra useless markup.
Chances are you're not setting the style on the correct element. It's probably being set somewhere up the line in a parent node.
elHighlight.style.backgroundColor = "";
elHighlight.style.backgroundImage = "";
You can also remove all the default styling by calling:
elHighlight.style.cssText = "";
In any case, you'll still have to do this on the specific element that is setting these properties, which means you may need to do a recursion on parentNode until you find it.
Try
elHighlight.style.removeProperty('background-color')
elHighlight.style.removeProperty('background-image')
have you tried elHightlight.style.background = "";?
I have a highlighter code on my site and this works
function highlight(id) {
var elements = getElementsByClass("softwareItem");
for (var ix in elements){
elements[ix].style.background = ""; //This clears any previous highlight
}
document.getElementById(id).style.background = "#E7F3FA";
}
An HTML element can have multiple CSS classes. Put your highlight information inside a CSS class. Add this class to your element to highlight it. Remove the class to undo the effect.

Categories

Resources