Check visibility before proceeding - javascript

Is it possible to do a callback for the below?
$('.element').css("visibility","visible");
I came across this but seems like there are issues using this in chrome.
$('.element').css("visibility","visible").promise().done(function(){
alert( 'done! start stuff...' );
});
Basically I'm looking for a way to confirm that the $('.element') is visible before proceeding to the next line.

Setting an element to be visible is synchronous so there is no reason or purpose to using a promise with that. There is nothing to wait for that to take effect.
$('.element').css("visibility","visible");
console.log($('.element').css("visibility")); // will show "visible" immediately
If, on the other hand, you want to wait for a repaint so the item is actually drawn on the screen, that is a different story. You will have to either force a repaint (which is a tricky non-standard thing to do in browsers these days as they try to avoid synchronous repaints) or you will have to use a slight delay with setTimeout() which allows a repaint to happen.

For making an element visible, try display:block or display:inline-block (and a bunch of other display properties other than display:hidden).
Here is a difference between display and visibility properties.
Also, making an element visible doesn't guarantee that it is visible to user since it could be child of hidden parent element. You can use visible selector of jquery to confirm the same.
$('.element').css("display","block");
if ( $('.element').is( ":visible" )
{
}

Related

Is there a more efficient way to show DOM element

I want to implement a simple menu just by using Vanilla JS. So I have a working onclick function, where I just twist visibility property on click of the menu item. CSS is by default set on visibility:hidden
function getContentP() {
var div = document.getElementById("menu1Content");
if (div.style.visibility === "hidden") {
div.style.visibility = "visible";
} else {
div.style.visibility = "hidden";
}
};
<a href="#menu1" onclick="getContentP()">
<h2>title</h2>
</a>
<!-- CONTENT BOX, show on clicks-->
<div id="menu1Content" style="background: #fefefe">
Some content to make it visible
</div>
This works as expected, but really slowly, and with poor results.
Any good suggestion to improve the code? And maybe add some nice transitions like fadeIn effect without using jQuery?
Thanks a lot.
Im not sure what slowly means in this case or what poor results you are seeing, but in general the thing that jumps out at me is the usage of onclick. When passing code like that to a dom element the runtime will essentially eval the snippet which is bad for a number of reasons, and certainly not great for performance (also likely can never be optimized by the vm).
element.addEventListener('click', function() { 'your stuff here' }, false);
may give you better performance but id be shocked if you can even tell the difference unless this is called thousands or maybe millions of times.
You could also cache the dom element since you seem be doing a lookup by id, then you dont have to do a potentially expensive dom search every time the thing is clicked.
I'm not css guru but you can probably get something cool with this without too much effort.
[from comments] I usually need two clicks on the link to get it to show in the first place, which is really strange
No, that is anything but strange.
element.style.property only allows you to access CSS values that where set either directly via a style attribute on the element, or by assigning a value to element.style.property via script.
Both is not the case here, and your class="hidden" that you had in your code initially (before editing it out) was likely to set the element’s visibility hidden from the stylesheet, right?
Therefor, when you check the current visibility of the element here for the first time,
if (div.style.visibility === "hidden") {
that condition is not true, so you set the visibility to hidden in your else-branch – and therefor the element stays hidden.
Now, on your second click, the value hidden was set via script, so now you can read it back. Now that if condition results in true, and your script sets the element to visible.
Easy way to work around this – turn the logic around:
Check div.style.visibility === "visible", and set the element to hidden if that’s true, and visible if it is false.
The element is hidden (via the stylesheet) when your page first loads. Because of what I explained before, div.style.visibility can’t read the value on the first click, so the condition will be false, and the element will be made visible.
The HTML (note the added id):
<a href="#" id="menu1Toggle" style="visibility: hidden;">
<h2>title</h2>
</a>
The handler (note the added ev and preventDefault()):
function getContentP(ev)
{
var div = document.getElementById("menu1Content");
div.style.visibility = div.style.visibility === "hidden" ? "visible" : "hidden";
ev.preventDefault();
};
Attach the event with:
document.getElementById("menu1Toggle").onclick = getContentP;
You could use opacity if you want to fadeIn/Out. Just add a CSS transition. An easy toggle method would be:
elem.style.opacity = +!parseInt(elem.style.opacity);
Not sure if this would perform better/worse, but here is a Fiddle

What are the drawbacks to using callbacks for synchronization of jQuery + CSS animation timing?

CodePen here : http://codepen.io/leifparker/pen/ogboag
I like to use CSS transitions whenever possible, but occasionally hit times where I want javascript code to run after a CSS animation has completed.
I have experimented with webkitTransitionEnd, but found it to be a bit flaky (as far as cross-browser reliability).
Setting a javascript timer, setInterval(), seems to be the age-old recommended method, but are there any concerns with utilizing an empty (ineffectual) jQuery .animation() callback?
$('.button').click(function(){
keepIndent = parseInt($('.kicker').css('text-indent'));
$('.kicker').toggleClass('active').animate({
textIndent : keepIndent
},300,function(){
$('.pebble').toggleClass('active');
});
});
I toggle the active class on .kicker, which animates it with CSS, and then on an (ineffective) .animate() callback, I toggle the class on .pebble. Obviously, the .animate(speed) must match the CSS-transition animation length, for a synchronized delay.
The keepIndent variable is used to make the animation visually ineffective, but could be skipped if a property that was not visibly used was assigned an arbitrary value (such as backgroundPositionX on an element without a background assigned).
This method seems valid, but I am concerned that there are cross-browser, or sequencing, pitfalls that are not immediately apparent.
Can you think of any reasons not to utilize this method?

DOM manipulation performance when toggle visibility

I have bunch of images in a wrapper div. I need to hide all of them except the one user clicks on.
What is the most performance concise way of doing that?
Should I apply class on all of them to hide them all and than filter out the one that was clicked and show only that one or should I loop over them all hiding them as loop progresses with exception of the one that was clicked or something else?
Tnx
In modern desktop browsers you won't see any difference. Browsers are tuned so that they are blazing fast in rendering any changes is DOM three. Guts tell me that it might be sligtly faster to loop through all images and set visibility depending on item clicked using style attribute and not using class. In that way you have to process only N elements and no external CSS files are involved. If you hide all and show the element with was clicked, you process N + 1 elements.
In your situation I would use solution that is fastest, more managable and clean from the developers standpoint as there won't be much difference in the final result if you use one method or another.
PS: If you're using jquery, you can use the following:
Lets say, your div has id='test-div', and there are several images in it. All these images can be accessed as:
$('#test-div img')
Now, lets assume you know the id of image which got clicked. Lets assume id='my-image'.
You can execute the following to hide all other images (except 'my-image'):
$('#test-div img').not('#my-image').addClass('hide')
One of the most performant ways would be to let CSS do the visibility. It sounds to me like you're only displaying one at a time, in which case you can do it with two DOM operations by using classes;
// scope above
var lastClicked = null;
// then in click listener, 1st param `e`
if (lastClicked) lastClicked.className = ''; // remove visible class
lastClicked = e.target; // get clicked node
lastClicked.className = 'visible'; // add visible class
I'm assuming event.target but depending how the listener is attached, you might want to use this or some other logic. Further, if you expect element.classList support, you can use add and remove from that.
Example CSS of how to show only nodes with class token visible.
selector:not(.visible) {
display: none;
}

What's the best way to test an element in the DOM

There are a couple of ways I could do this (That I'm aware of).
Test css display
if ($('#foo').css('display') == 'none')
Test the visibility
if ($('#foo').is(':visible'))
In the visibility I can check if the element is there.
Elements are considered visible if they consume space in the document.
Visible elements have a width or height that is greater than zero.
Elements with visibility: hidden or opacity: 0 are considered visible,
since they still consume space in the layout.
Source
But, note that in both I can't test the visibility (by the user) because:
Hiding an element can be done by setting the display property to
"none" or the visibility property to "hidden". However, notice that
these two methods produce different results:
visibility: hidden hides an element, but it will still take up the same
space as before. The element will be hidden, but still affect the
layout.
display: none hides an element, and it will not take up any space. The
element will be hidden, and the page will be displayed as if the
element is not there:
Source
So in neither of the examples I test if the element is visible in all senses for the user.
So my question is:
What're the differences between the two if's codes from above?
What's the best way to test if an element is visible to the user:
Should I have to use something like:
if ($('#foo').is(':visible') &&
$('#foo').css('opacity') > 0 &&
$('#foo').css('visibility') != 'hidden')
I think your best bet is to implement a custom function like below and test/improve as new things come up,
$.fn.isReallyVisible = function () { //rename function name as you like..
return (this.css('display') != 'none' &&
this.css('visibility') != 'hidden' &&
this.css('opacity') > 0);
}
The above should be cross browser proof as we are using jQuery .css function (specifically for opacity).
DEMO
The difference between the two is that being hidden using "visible" attribute leaves the element on the page, just not actually displayed. So, it's spacing will be taken into account when the page renders the rest of the display.
It seems that doing it the other way actually stops the element from being put onto the page, which can change how other elements on the page are laid out.
usually testing the visible part is enough from my experience, but if you are wanting to be more complete, then yeah you would have to check using "&&" conditions on multiple attributes.
It really all depends on how clean the code you are using is, and how well tested the rest of the UI aspect of the system is.
The other thing to consider is what is the purpose of the test. Are you testing code that you wrote, or how the browser is using Javascript to render the page? You want to be testing the code that you are creating, and rely on the fact that the browser works (because if the browser stops working, then the whole thing is unreliable anyway). So if your code tells the element to set some attribute, then checking for that attribute is all the testing you need to do. Anything on top of that can only really be proven by testing outside of the code itself (as in manualy looking at the page and other things like that).
If you want to see if an element exists in the DOM you could just do this:
$.fn.exists = function () {
return this.length > 0;
}
Usage:
$('#myid').exists();

jQuery hide and show not properly (multiple times)

I'm having a problem with my project, on combination with jQuery/Coffeescript.
On my homepage I have a block with text, with an arrow underneath it.
Under there, there are buttons, and every time I have my mouse over one of those buttons, I want the text block + arrow to move.
I do this with the jQuery UI library, with the method hide and show.
In my CSS code I made several classes: .position1, .position2 and .position1. Every time over hover with my mouse over one of the buttons, I want the text block to move to a specific position, so I change it's class (if someone has a better solution, I would gladly like to hear it).
Now the problem I'm having, is that sometimes the arrow hides and appears multiple times after each other (especially when I move my mouse very fast between the buttons)
A simple (partial) version of my jQuery is as follows:
var appear_arrow = function(to_position, show_delay) {
removeClasses($('.arrow'));
$('.arrow').addClass(to_class);
$('.arrow').delay(show_delay).show('slide', 'slow');
};
var to_position1 = function() {
$('.arrow').hide(0);
$('.text_block').hide(appear);
switchClass($('.text_block'));
$('.text_block').show(appear);
appear_arrow('position1', delay);
};
$('.button1').hover(
function() {
to_position1();
},
function() {}
);
My question, does anybody know why sometimes the arrow is appearing multiple times. Or does someone has a suggestion how to better do this?
jQuery queues up all its animations on a given Element rather than resetting it first.
$("selector").stop(); // stops animations on matched elements and resets queue
A stop().fadeIn('slow') however will start from the opacity the element had when you called stop, which could be solved by for example hiding/showing it immediately, then doing a full fade at the new location - whatever looks best for you.
On a side note:
Seems you wrote wrapper functions for jQuery's removeClass and toggleClass methods.
removeClass() if called without arguments removes all classes, so you could possibly just use those if in a jQuery context anyway (assuming your methods have no extra functionality).
Seeing how often you call $('.arrow') you may want to cache your selectors, at least per iteration, then pass it to appear_arrow().
var $arrow = $('.arrow')

Categories

Resources