Hiding a div when clicking out of it - javascript

I added code to make a div, #pending-friend-list-dropdown, close when clicking outside of it. This works fine, but now when clicking on my image div, friend-icon, the drop-down div will not close now.
As you can see in my snippet, the image div is what opens the drop-down box. I am just trying to figure out how that image div can be used to open and close the drop-down, while using the mouseup function to close the drop-down div as well.
//Hiding Pending Friend Drop-down when clicking out of it
$(document).mouseup(function (e)
{
var container = $("#pending-friend-list-dropdown");
var friend_icon = $("#friend-icon");
if (!container.is(e.target) // if the target of the click isn't the container...
&& container.has(e.target).length === 0) // ... nor a descendant of the container
{
container.hide();
}
else if (friend_icon.has(e.target)) {
container.hide();
}
});
//Toggle Pending Friend List
$("#friend-icon").click(function() {
$('#pending-friend-list-dropdown').toggle(100);
});
#main-bar {
width: 85%;
height: 60px;
position: relative;
margin-left: 15%;
background: red;
padding: 3px 0;
}
#main-bar-container {
border: 1px solid black;
margin: 0 10px;
position: relative;
width: 95%;
height: 56px;
left: 2%;
}
/*---- Pending Friends List----*/
#friend-icon {
display: inline-block;
cursor: pointer;
position: absolute;
right: 20%;
top: 15px;
}
#friend-icon img {
height: 30px;
width: 30px;
}
#pending-friend-list-dropdown {
height: 500px;
width: 400px;
overflow: scroll;
z-index: 100000;
position: absolute;
left: 70%;
top: 70px;
background: blue;
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="main-bar">
<div id="main-bar-container">
<div id="friend-icon"><img src="../icons/collection/social.png" alt="Pending Friends"></div>
</div>
</div>
<div id="pending-friend-list-dropdown">
</div>

You can achieve this more simply by running the code whenever someone clicks on the html-element (the entire page).
Then check if the click is located on certain elements.
There is also no need to give the instructions in two places for what to be done when clicking on "#friend-icon". I have removed the second instance of this in the below code, and just moved the .toggle up to the if statement.
It now works like a charm:
$("html").click(function(event)
{
var container = "#pending-friend-list-dropdown";
var friend_icon = '#friend-icon, #friend-icon img';
if ( $(event.target).is(friend_icon) ) // clicking on the toggler-div or the img it contains
{
$(container).toggle(100);
}
else if (!$(event.target).is(friend_icon) // clicking outside of the toggler
&& !$(event.target).is(container)) // and outside of the toggled div itself
{
$(container).hide();
}
});
Here's a jsfiddle: https://jsfiddle.net/r54ardcz/2/

I'll give a third option just so that all the ones I know are on this site. This is the option that Office Fabric UI uses (https://dev.office.com/fabric#/components/contextualmenu) where I think #zheer-mchammer-husain's answer is more along the Twitter Bootstrap model.
Essentially you create a layer over your whole page (height: 100vh and width: 100vw; position: fixed) and then put your dropdown content inside that layer. When the user clicks that layer, it closes the whole layer at once disappears and all is done.

Related

Move relative object position when scrollbar appears using CSS

On my page, I'm displaying a log file in a div element with overflow-y:auto. In the top right corner of the div, I'm overlaying a close button div with position:relative.
When the scrollbar appears, the button is overlaying the scrollbar which is hard to see and looks ugly. You can see an example here: https://jsfiddle.net/4azw0rLf/
Moving it with javascript when scrollHeight exceeds clientHeight feels like a hack. Is there an option in CSS to move the close button to the left for the width of the scrollbar as soon as it appears?
You can wrap your terminal and move your close button inside. I created a minimal example starting from your code.
EDIT
With the first answer the close button scrolled along with the text, I corrected using the position: sticky; and top:0px;
It is not compatible with all browsers, but with most, you can check compatibility here.
const terminal = document.getElementById("terminal");
addText = () => {
terminal.innerHTML += "overflowing line<br>";
}
#container-terminal {
position: relative;
overflow-y: auto;
border: 2px solid;
height: 100px;
width: 200px;
}
#terminal {
position: absolute;
height: 100%;
width: 100%;
}
#closeBtn {
background-color: red;
position: -webkit-sticky;
position: sticky;
top:0px;
width: 20px;
display: inline-block;
float: right;
}
<div onclick="addText()" style="cursor:pointer;">Click to add text</div><br>
<div id="container-terminal">
<div id="terminal">CSS only<br>CSS only<br>CSS only<br>CSS only<br>CSS only<br></div>
<div id="closeBtn">X</div>
</div>

Changing the order in which <div>'s overlap each other with jQuery mouse-click events

I'm trying to make specified div's on my page interactive and thus, change focus (come to the foreground if you will) when clicked. Essentially, I would like the div's to act much like the windows do on a computer running Microsoft Windows.
This is what I've come up with so far using z-index and it does work, sort of. The problem is that the div's appear to have their own "order" so to speak when it comes to overlapping each other based on where they are placed in the HTML.
For instance, if you click "Div2" then "Div1", you can see that "Div2" ends up actually going back behind "Div3" rather than staying in front of it as it previously was. I'd like order to be retained as clicked. If you click Div2, it should be in the front, then you click Div1 and it would then be in front of Div2, etc.
Any ideas on a way around this would be greatly appreciated. Thank you in advance!
// Global vars
var lastFocused;
// When left mousedown on a ".window" element, remove the ".window-focus" class from id
// specified in the global var "lastFocused". Next, update the global var "lastFocused"
// with the most recently clicked element id. Lastly, add the ".window-focus" class to
// the id specified in global var "lastFocused".
$('.window').mousedown(function () {
$(lastFocused).removeClass('window-focus');
lastFocused = "#" + $(this).attr("id");
$(lastFocused).addClass('window-focus');
});
// Make all ".window" elements resizable and draggable.
$('.window').draggable({containment: '#container'}).resizable({containment: '#container'});
html, body, #container {
height: 100%;
width: 100%;
font-family: Roboto;
background-color: #333;
color: #c9c9c9;
font-size: 1em;
overflow: hidden;
}
.window {
position: absolute !important;
border: 1px solid #999;
background-color: #222;
height: 100px;
width: 100px;
z-index: 1;
}
#div1 { top: 20px; left: 20px; }
#div2 { top: 60px; left: 60px; }
#div3 { top: 100px; left: 100px; }
.window-focus { z-index: 2; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
<div class="window" id="div1">ONE</div>
<div class="window" id="div2">TWO</div>
<div class="window" id="div3">THREE</div>
Your issue is that you are always giving the the currently clicked div a z-index of 2, which does bring it to the front, but then when you remove that class from an element it simply goes back to it's original z-index. You need that last-applied z-index not to change and have the next-clicked element get a z-index that is one higher than the previous one.
Just keep track of the last z-index assigned to the last-clicked div element and increment it by one after each assignment so that the next clicked element will get a higher z-index assigned to it.
NOTES:
There is no need for the lastFocused variable, the .window-focus
CSS selector, or to assign a z-index:1 to the .window elements.
You were exactly right about elements having an implicit z-index
based on where they are in the HTML. For sibling elements, the z-index is simply based on the sequence. The earlier in the sequence, the lower the z-index. But, it's more complex when you start working with elements that don't share the same parent. See the stacking context for details.
JQuery recommends using the element.on("eventName", callback)
method rather than event-specific methods (i.e.
element.mousedown(callback)).
It's probably not a good idea to use a class name of .window for
elements that are not the window object. It will cause confusion. For something like this, a class name of stackable or draggable seems appropriate.
var highestZ = 3; // There are 3 divs, so highest z-index in use is initially 3
// When any of the div.stackable elements get clicked...
$('.stackable').on("mousedown", function () {
$(this).css('z-index', ++highestZ); // Clicked div gets a z-index one higher than prevous highest
});
// Make all ".stackable" elements resizable and draggable.
$('.stackable').draggable({containment: '#container'}).resizable({containment: '#container'});
html, body, #container {
height: 100%;
width: 100%;
font-family: Roboto;
background-color: #333;
color: #c9c9c9;
font-size: 1em;
overflow: hidden;
}
.stackable {
position: absolute !important;
border: 1px solid #999;
background-color: #222;
height: 100px;
width: 100px;
user-select:none;
cursor:pointer;
}
#div1 { top: 20px; left: 20px; }
#div2 { top: 60px; left: 60px; }
#div3 { top: 100px; left: 100px; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
<div class="stackable" id="div1">ONE</div>
<div class="stackable" id="div2">TWO</div>
<div class="stackable" id="div3">THREE</div>

How can I allow a click to pass through a div but still react to hover?

Say I have divA that partially overlaps divB. How can I allow clicks on divA to pass through to divB but still have hover fired when hovering over divA?
I'm aware of pointer-events:none; and this makes the clicks pass through but it also prevents the hover.
I have also tried the below, but it did not allow clicks to fall through
$(document).on('click', '.feedback-helper', function(e){
e.preventDefault();
})
Picture the relation of the divs like:
Here is the why of it (read as: "let's avoid an X Y problem"):
I'm working on an implementation of feedback.js
To see the issue:
view the feedback.js demo
click the feedback button in the bottom right
draw a box on the screen to highlight a section
click the "black out" button
try to draw a box inside the first box you can't because the click is blocked by the first box
I need to allow drawing a blackout box over a highlighted area but if I set pointer-events:none; I will lose other hover functionality I have on those elements.
Here is a jsFiddle example
All solutions welcome
I checked your example page and if you set a slightly lower z-index on data-type="highlight" that could take care of the problem, try a z-index of 29990 in comparison to your current 30000. This should allow you to target the highlighted feedback area and overlay it with the blackout elements.
You could get the click event for the overlaying element to initiate the click event for the underlying element.
Native JS Example:
document.getElementById('divA').addEventListener('click', function() {
alert('Clicked A');
});
document.getElementById('divB').addEventListener('click', function() {
var event = document.createEvent('HTMLEvents');
event.initEvent('click', true, false);
document.getElementById('divA').dispatchEvent(event);
});
div {
cursor: pointer;
border: 1px solid black;
}
#divA {
height: 300px;
width: 300px;
background: whitesmoke;
}
#divB {
height: 30px;
width: 30px;
background: grey;
position: absolute;
left: 100px;
top: 100px;
}
#divB:hover {
background: green;
}
<div id="divA"></div>
<div id="divB"></div>
jQuery Example:
$('#divA').on('click', function() {
alert('Clicked A');
});
$('#divB').on('click', function() {
$('#divA').trigger('click');
});
div {
cursor: pointer;
border: 1px solid black;
}
#divA {
height: 300px;
width: 300px;
background: whitesmoke;
}
#divB {
height: 30px;
width: 30px;
background: grey;
position: absolute;
left: 100px;
top: 100px;
}
#divB:hover {
background: green;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="divA"></div>
<div id="divB"></div>
Another option is to use a pseudo element instead. Perhaps that will do what you need.
$('#toggleBlack').on('click', function() {
$('#divA').toggleClass('hidden');
});
div {
border: 1px solid black;
}
#divA {
background: whitesmoke;
position: relative;
}
#divA.hidden:before {
position: absolute;
content: ' ';
top: 0;
left: 0;
right: 0;
bottom: 0;
background: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="divA">Highlight the text once I'm hidden and cut/copy/drag</div>
<br />
<br />
<button id="toggleBlack">Toggle Hidden</button>

Moving a button with ng-class

So I have this button which, when clicked upon, should move 480px to the right and change icon. I am using Angular JS and the changing of the icon works, but the button does not move.
This my is my HTML:
<div id="menuButton" ng-click="toggleMenu()">
<div class="hamburgerMenuButton" ng-class="menu.shown ? 'menuOpen' : 'menuClosed'">
</div>
</div>
CSS:
#menuButton {
width:52px;
height: 50px;
padding: 10px;
z-index: 1000;
position: relative;
}
#menuButton:hover {
background-color: #02CDED;
border-color: #FFFFFF;
}
.hamburgerMenuButton {
width: 32px;
height: 30px;
}
.menuOpen {
left: 480px;
background-image: url('images/arrow.png');
}
.menuClosed {
background-image: url('images/hamburger.png');
}
When I look in the developers view in Chrome I can see that the class changes on the hamburgerMenuButton div, and the property left: 480px; is added, but it just does not move. The icon does change as expected.
Add position:relative;, or position:inherit;, to the .hamburgerMenuButton.
It's not moving because it has position set to static, per default. The left does not mean anything to the element.
Though you've set position:relative; on the parent div, it just so happens that position is not an inherited property;

Map not taking up whole of div

I'm using geocoding to display a google map with the users location displayed. I'm looking the map to be situated with a sliding menu. The problem I have is when you open out the sliding menu the map only takes up a small area in the top left corner, but as soon as you resize the browser window the map takes up the full area like I want it to. This happens no matter what way you resize the browser window even by making it smaller. Let me know if you need to see more of my code than this:
Sliding menu function
$(document).ready(function()
{
$(".content").hide(); //updated line, removing the #panel ID.
$('#tab').toggle(function() //adding a toggle function to the #tab
{
$('#panel').stop().animate(
{
width:"800px", opacity:0.8 //to adjust width of bar
}
, 500, function() //sliding the #panel to 200px
{
$('.content').fadeIn('slow'); //slides the content into view.
});
},
function() //when the #tab is next cliked
{
$('.content').fadeOut('slow', function() //fade out the content
{
$('#panel').stop().animate(
{
width:"0", opacity:0.1 //slide the #panel back to a width of 0
}
, 500);
});
});
});
Sliding menu html
<div id="panel">
<div class="content">
<div id="mapContainer"></div>
</div>
</div>
CSS
#tab {
width: 30px;
height: 100px;
position: fixed;
left: 0px;
top: 100px;
display: block;
cursor: pointer;
background-color: #ff0000;
border-top-right-radius: 20px;
border-bottom-right-radius: 20px;
}
#panel {
position: fixed;
left: 0px;
top: 50px;
background-color: #ffffff;
height: 500px;
width: 0px;
border-top-right-radius: 20px;
border-bottom-right-radius: 20px;
}
#mapContainer {
height: 500px;
width: 800px;
border:10px solid #eaeaea;
}
The map container requires a width and height to correctly display the map but it seems the animations are interfering with the values.
The map works when the browser is resized as the width and height are correctly set and the resize event is raised.
The quickest solution to your problem would be to call the resize method when the animation has finished as so:
google.maps.event.trigger(map, 'resize');
JSFiddle Update: http://jsfiddle.net/uADHv/2/

Categories