Click outside of element to hide element - javascript

My code does this: when element .pencil is clicked on, it toggles the hidden element .pencilpanel. When clicked outside of this .test element (there are two .test elements), then this .pencilpanel should hide.
However, my problems are that:
1) When the second .test element is clicked on, the first .test element remains visible when it should be hidden. And,
2) When the first .pencil element is clicked on, and its corresponding .pencilpanel is also clicked on, it will hide .pencilpanel, when it's supposed to remain visible. Any element that is currently visible within .test, and if clicked on, should not be hidden, unless that clicked on element lies outside of the current .test element.
So I'm not getting why when a click is made on .pencilpanel, it hides it on this line if(!$(this).closest('.test').length && $('.pencilpanel').is(":visible")) {. And the fact that the first .pencilpanel remains visible when it should be hidden whenever another .pencil is clicked on. This is my code:
$(document).ready(function () {
$('.pencil').on('click', function (event) {
event.stopPropagation();
$(this).parent(".btsdiv").next(".fcmdiv").children(".pencilpanel").toggleClass("displayblock");
});
});
$(document).ready(function () {
$(document).click(function () {
if (!$(this).closest('.test').length && $('.pencilpanel').is(":visible")) {
$('.pencilpanel').removeClass("displayblock");
}
});
});
.pencilpanel {
display: none;
}
.displayblock {
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="test">
<div class="btsdiv">
<div class="pencil">✎</div>
</div>
<div class="fcmdiv">
<div class="pencilpanel">
<textarea></textarea>
</div>
</div>
</div>
<div class="test">
<div class="btsdiv">
<div class="pencil">✎</div>
</div>
<div class="fcmdiv">
<div class="pencilpanel">
<textarea></textarea>
</div>
</div>
</div>

You can use the document.activeElement to check before you close the panels. Please find the modified code.
$(document).ready(function() {
$('.pencil').on('click', function(event) {
event.stopPropagation();
closePanel();
$(this).closest(".test").find(".pencilpanel").toggleClass("displayblock");
});
$(document).on("click", function() {
if (document.activeElement.tagName != 'TEXTAREA')
closePanel();
});
});
function closePanel() {
$('.pencilpanel').removeClass("displayblock");
}
.pencilpanel {
display: none;
}
.displayblock {
display: block;
}
<script src="https://code.jquery.com/jquery-3.4.1.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
<div class="test">
<div class="btsdiv">
<div class="pencil">✎</div>
</div>
<div class="fcmdiv">
<div class="pencilpanel">
<textarea></textarea>
</div>
</div>
</div>
<div class="test">
<div class="btsdiv">
<div class="pencil">✎</div>
</div>
<div class="fcmdiv">
<div class="pencilpanel">
<textarea></textarea>
</div>
</div>
</div>

$(document).ready(function () {
$('.pencil').on('click', function (event) {
event.stopPropagation();
$('.pencilpanel').removeClass("displayblock");
$(this).parent().siblings().children(".pencilpanel").addClass("displayblock");
});
$(".pencilpanel").click(function () {
event.stopPropagation();
});
$(document).click(function () {
$('.pencilpanel').not(":focus").removeClass("displayblock");
});
});

$(document).ready(function () {
$('.pencilpanel').hide();
$('.pencil').on('click', function (event) {
event.stopPropagation();
var elm=$(this).parent(".btsdiv").next(".fcmdiv").children(".pencilpanel");
$('.pencilpanel').not(elm).hide();
if(elm.css('display') == 'none') elm.css('display','inline-block');
else elm.css('display','none');
});
$("*").on('click',function (event) {
event.stopPropagation();
if($(this).hasClass("pencil")) return;
if($(this).hasClass("pencilpanel")) return;
if($(this).parent().hasClass("pencilpanel")) return;
$('.pencilpanel').hide();
});
});
.pencil {
cursor: pointer;
}
.pencil, .pencilpanel {
display: inline-block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="test">
<div class="btsdiv">
<div class="pencil">✎</div>
</div>
<div class="fcmdiv">
<div class="pencilpanel">
<textarea></textarea>
</div>
</div>
</div>
<div class="test">
<div class="btsdiv">
<div class="pencil">✎</div>
<br>
</div>
<div class="fcmdiv">
<div class="pencilpanel">
<textarea></textarea>
</div>
</div>
</div>

Related

Javascript if hasclass, alert "yes", else alert "no"

I'm creating a multiple choice quiz where the answer is dragged and placed in a div. I want to make it so that if the correct answer is dragged into the div, then an alert will show up saying "yeah". If the wrong answer is dragged into the div, then the alert will say "noh".
I've tried using an if statement with the condition "hasClass". With the correct answer having the right class. Here is my code:
$(function() {
$(".ui-widget-content").draggable();
$(".ui-widget-content2").draggable();
$("#droppable").droppable({
drop: function(event, ui) {
if ($("div").hasClass("ui-widget-content") === true) {
alert("Yeah");
} else {
alert("noh");
}
}
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.js"></script>
<p>hello <span id="droppable" class="ui-widget-header"><span></span>
</span>thank you</p>
<div id="draggable" class="ui-widget-content">
<p>vrother</p>
</div>
<div id="draggable" class="ui-widget-content2">
<p>sister</p>
</div>
<div id="draggable" class="ui-widget-content">
<p>dude</p>
</div>
Currently, the if part works (the alert says yeah when the correct answer is dragged). But when the wrong answer is dragged onto the div, nothing happens. I believe there must be something wrong with my else condition.
The problem is that you not targeting the div you dropped, try with:
if($(ui.draggable).hasClass("ui-widget-content") === true) {
alert("Yeah");
} else {
alert("noh");
}
Demo
$(function() {
$(".draggable").draggable();
$("#droppable").droppable({
drop: function(event, ui) {
if ($(ui.draggable).hasClass("ui-widget-content2")) {
console.log("Yeah");
} else {
console.log("noh");
}
}
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<div class="ui-widget-content draggable">
<p>Drag me to my target</p>
</div>
<div id="droppable" class="ui-widget-header">
<p>Drop here</p>
</div>
<div class="ui-widget-content ui-widget-content2 draggable">
<p>Drag me to my target ui-widget-content2</p>
</div>
I think the problem comes from the fact that you have hardcoded a selector in your callback:
if($( "div" ).hasClass
Since your first div has the class, you will never enter the else statement.
You should define this selector dynamically:
if($(ui.draggable).hasClass
$(function() {
$(".ui-widget-content").draggable();
$(".ui-widget-content2").draggable();
$("#droppable").droppable({
drop: function(event, ui) {
if ($(ui.draggable).hasClass("ui-widget-content") === true) {
alert("Yeah");
} else {
alert("noh");
}
}
});
});
#droppable {
display: inline-block;
width: 300px;
height: 15px;
background: tomato;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<p>hello <span id="droppable" class="ui-widget-header"><span></span>
</span>thank you</p>
<div id="draggable" class="ui-widget-content">
<p>vrother</p>
</div>
<div id="draggable" class="ui-widget-content2">
<p>sister</p>
</div>
<div id="draggable" class="ui-widget-content">
<p>dude</p>
</div>

Vue.js - Add delete button on hover and delete it on button press

I have the below data coming from another server which is not in my control and when displaying it in the browser I have to provide a solution to
1) Show delete button for the class childElement on hover
2) Click on delete button and delete that childElement div
Is there any way I can do it using CSS/JS or Vuejs ( Dynamically adding Delete button on hover and delete the element on button click) ? Thank You
.childElement {
width:100px;
height:100px;
background-color:#f3f3f3;
margin-top:10px;
padding:10px;
}
<div id="videos">
<div class="childElement">
first div
</div>
<div class="childElement">
second div
</div>
<div class="childElement">
third div
</div>
</div>
Your work basically boils down to some script that will find all the elements and auto append elements with listeners.
const childElements = document.querySelectorAll('.childElement');
childElements.forEach(childElement => {
// create button for each childElement
const deleteButton = document.createElement('button');
deleteButton.setAttribute('hidden', '');
deleteButton.innerText = "Click to delete";
// append button to the childElement
childElement.appendChild(deleteButton);
// add event listeners
childElement.addEventListener('mouseenter', event => {
deleteButton.removeAttribute('hidden');
});
childElement.addEventListener('mouseleave', event => {
deleteButton.setAttribute('hidden', '');
});
deleteButton.addEventListener('click', event => {
childElement.setAttribute('hidden', '');
});
});
.childElement {
width: 100px;
height: 100px;
background-color: #f3f3f3;
margin-top: 10px;
padding: 10px;
}
<div id="videos">
<div class="childElement">
first div
</div>
<div class="childElement">
second div
</div>
<div class="childElement">
third div
</div>
</div>
You could add an array to your data object called childDivs and which item inside that array contains a boolean showBtn intilially its value is false and the text to be shown inside the div element
UPDATE :
the above described logic could be useful when you could control the data in front-end, but according to the OP's use case, we could add the script given by #GenericUser inside the mounted hook.
new Vue({
el: '#app',
data() {
return {
childDivs: [{
text: 'First',
showBtn: false
},
{
text: 'Second',
showBtn: false
},
{
text: 'Third',
showBtn: false
}
]
}
},
methods: {
remove(i) {
this.childDivs.splice(i, 1)
}
},
mounted() {
const childElements = document.querySelectorAll('.childElement');
childElements.forEach(childElement => {
const deleteButton = document.createElement('button');
deleteButton.setAttribute('hidden', '');
deleteButton.innerText = "delete";
deleteButton.classList.add("btn")
deleteButton.classList.add("btn-danger")
childElement.appendChild(deleteButton);
childElement.addEventListener('mouseenter', event => {
deleteButton.removeAttribute('hidden');
});
childElement.addEventListener('mouseleave', event => {
deleteButton.setAttribute('hidden', '');
});
deleteButton.addEventListener('click', event => {
childElement.setAttribute('hidden', '');
});
});
}
})
.childElement {
width: 100px;
height: 100px;
background-color: #f3f3f3;
margin-top: 10px;
padding: 10px;
}
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<link type="text/css" rel="stylesheet" href="//unpkg.com/bootstrap/dist/css/bootstrap.min.css" />
<div id="app" data-app>
<div id="videos">
<div class="childElement">
first div
</div>
<div class="childElement">
second div
</div>
<div class="childElement">
third div
</div>
</div>
</div>
Try this code
also use jquery to you project
here like this
<script
src="https://code.jquery.com/jquery-3.3.1.min.js"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
crossorigin="anonymous"></script>
<div id="videos">
<div class="childElement" id="divOne" >
<div id="delete">X</div>
first div
</div>
<div class="childElement">
second div
</div>
<div class="childElement">
third div
</div>
</div>
<script>
$(document).ready(function(){
$("#divOne").hover(function(){
$(this).css("visibility", "visible");
}, function(){
$(this).css("visibility", "hidden");
});
$("#delelte").on("click",()=>{
$("#divOne").children().remove();
});
});
</script>
You can try this one with jQuery:
$('body').on('mouseenter', '.childElement', function(e){
$(this).append('<div class="remove">remove it</div>');
$('.childElement').on('mouseleave', function(){
$('.remove').remove();
});
$('body').on('click', '.remove', function(e){
$(this).parent().remove();
});
});
.childElement {
width:100px;
height:100px;
background-color:#f3f3f3;
margin-top:10px;
padding:10px;
}
.remove {
position:absolute;
width: 100px;
height: 30px;
background: #000;
color:#fff;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="videos">
<div class="childElement">
first div
</div>
<div class="childElement">
second div
</div>
<div class="childElement">
third div
</div>
</div>

Javascript SlideUp with multiple div

Right now, I can only have one filter active. If I try to click on the other filter, it cancels the first one. How can I make them both stay active?
This is my code:
https://jsfiddle.net/0x43v59b/2/
html:
<div class="header-box">
<div class="header-click">
<h5>Publish Year</h5>
</div>
<div class="no-display">
<p>test1</p>
</div>
</div>
<div class="header-box">
<div class="header-click">
<h5>Condition</h5>
</div>
<div class="no-display">
<p>test2</p>
</div>
</div>
<script>
$('.header-click').on('click', function() {
$parent_filter = $(this).closest('.header-box');
$parent_filter.siblings().find('.no-display').slideUp();
$parent_filter.find('.no-display').slideToggle(500, 'swing');
});
</script>
css:
.header-click {
cursor: pointer;
}
.no-display {
display: none;
}
.header-box {
margin-bottom: 15px;
}
You just need to get rid of this line:
$parent_filter.siblings().find('.no-display').slideUp();
Its checking all siblings with class '.no-display' and sliding them up
<script>
$('.header-click').on('click', function() {
$parent_filter = $(this).closest('.header-box');
//$parent_filter.siblings().find('.no-display').slideUp();
$parent_filter.find('.no-display').slideToggle(500, 'swing');
});
</script>
$('.header-click').on('click', function() {
$(this).parent().find('.no-display').slideToggle(500,'swing');
});
here is the updated jquery function:
$('.header-click').on('click', function() {
$parent_filter = $(this).closest('.header-box');
//$parent_filter.siblings().find('.no-display').slideUp();
$parent_filter.find('.no-display').slideToggle(500, 'swing');
});
You can use this code, works well for your condition:
$('.header-click').on('click', function() {
$parent_filter = $(this).next('.no-display');
if ($parent_filter.is(":hidden")) {
$parent_filter.slideDown();
} else {
$parent_filter.slideUp();
}
});
.header-click {
cursor: pointer;
}
.no-display {
display: none;
}
.header-box {
margin-bottom: 15px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!-- Year Filter -->
<div class="header-box">
<div class="header-click">
<h5>Publish Year</h5>
</div>
<div class="no-display">
<p>test1</p>
</div>
</div>
<!-- Condition Filter -->
<div class="header-box">
<div class="header-click">
<h5>Condition</h5>
</div>
<div class="no-display">
<p>test3</p>
</div>
</div>
All above answers look correct to me, Just one more way to achieve this.
$('.header-click').on('click', function() {
$(this).next(".no-display").slideToggle(500, 'swing');
});
Here is the script i made, hope this is exaclty what you want.
<script>
$(document).ready(function(){
$(document).on('click','.header-click',function(){
$(this).next().slideToggle(500,'swing');
});
});
</script>

Refactoring jQuery repeating pattern

I have painted my self into a corner in order to quickly prototype.
What's the best way to refactor the following jQuery code? Its functionality is to toggle between some sidebar navigation items. I need it to be more dynamic in order to be scalable.
Would you add the IDs inside the if statements, in an array and iterate through them? Use variables? Create a function and call it on the html side onClick? No matter what I think of, it stills leads to a bunch of repeating code.
Thank you!
// TOGGLING LEFT NAVIGATION
$('#settingsClick').click(function() {
if( $('#addContainer, #noteContainer, #logoContainer, #themeContainer').is(':visible') ) {
$('#addContainer').slideUp(350);
$('#noteContainer').slideUp(350);
$('#logoContainer').slideUp(350);
$('#settingsContainer').slideDown(350);
$('#themeContainer').slideUp(350);
} else {
$('#settingsContainer').slideToggle(350);
}
});
$('#addClick').click(function() {
if( $('#settingsContainer, #noteContainer, #logoContainer, #themeContainer').is(':visible') ) {
$('#settingsContainer').slideUp(350);
$('#noteContainer').slideUp(350);
$('#logoContainer').slideUp(350);
$('#addContainer').slideDown(350);
$('#themeContainer').slideUp(350);
} else {
$('#addContainer').slideToggle(350);
}
});
$('#noteClick').click(function() {
if( $('#settingsContainer, #addContainer, #logoContainer, #themeContainer').is(':visible') ) {
$('#settingsContainer').slideUp(350);
$('#addContainer').slideUp(350);
$('#logoContainer').slideUp(350);
$('#noteContainer').slideDown(350);
$('#themeContainer').slideUp(350);
} else {
$('#noteContainer').slideToggle(350);
}
});
$('#logoClick').click(function() {
if( $('#settingsContainer, #addContainer, #noteContainer, #themeContainer').is(':visible') ) {
$('#settingsContainer').slideUp(350);
$('#addContainer').slideUp(350);
$('#noteContainer').slideUp(350);
$('#logoContainer').slideDown(350);
$('#themeContainer').slideUp(350);
} else {
$('#logoContainer').slideToggle(350);
}
});
$('#themeClick').click(function() {
if( $('#settingsContainer, #addContainer, #noteContainer, #logoContainer').is(':visible') ) {
$('#settingsContainer').slideUp(350);
$('#addContainer').slideUp(350);
$('#noteContainer').slideUp(350);
$('#logoContainer').slideUp(350);
$('#themeContainer').slideDown(350);
} else {
$('#themeContainer').slideToggle(350);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<a id="settingsClick">Click Me</a><br>
<div id="settingsContainer">Content...</div>
<br><br>
<a id="addClick">Click Me</a><br>
<div id="addContainer">Content...</div>
<br><br>
<p> Etc... Etc....</p>
You should group using the common CSS class, i.e. header and content. Using the established relationship you can target the others content holder and content associated with the current clicked header element.
$('.container .header').on('click', function() {
//Get the current element
var $this = $(this);
//find the content
var $content = $this.closest('.container').find('.content'); //$this.next()
//get all contents
var content = $('.container .content');
//Slide up others
content.not($content).slideUp(350);
//Slide down
$content.slideToggle(350);
});
.content {
display: none
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<div class="header" id="settingsClick">Click Me</div>
<div class="content" id="settingsContainer">Content...</div>
</div>
<div class="container">
<div class="header" id="addClick">Click Me</div>
<div class="content" id="addContainer">Content...</div>
</div>
<div class="container">
<div class="header" id="noteClick">Click Me</div>
<div class="content" id="noteContainer">Content...</div>
</div>
the best bet would be to do it like so
$(document).on('click', ".trigger", function() {
var sibling_content = $(this).siblings(".content");
if (!sibling_content.hasClass('active')) {
$(".content").slideUp('slow').removeClass('active');
sibling_content.slideDown('slow').addClass('active');
} else {
sibling_content.slideUp('slow').removeClass('active');
}
})
.trigger {
background-color: red;
color: white;
font-size: 16px;
}
.content {
background-color: blue;
color: white;
font-size: 16px;
padding: 20px 0;
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<div class="trigger">trigger</div>
<div class="content">content</div>
</div>
<div class="container">
<div class="trigger">trigger</div>
<div class="content">content</div>
</div>
<div class="container">
<div class="trigger">trigger</div>
<div class="content">content</div>
</div>
<div class="container">
<div class="trigger">trigger</div>
<div class="content">content</div>
</div>

detect click, check attribute value and text inside, and display element

I need to detect click of an element(.menuitem), check the text it contains.
And then based on the attribute(is-checked), hide or show other elements.
I need this only when clicking that other button.
<div class="items">
<div class="menuitem" is-checked="true">
<div class="ytp-menuitem-label">Button 1</div></div>
<div class="menuitem" is-checked="false">
<div class="ytp-menuitem-label">Button 2</div></div>
</div>
<div class="element">some content</div>
<div class="element">some more content</div>
$('.menuitem').click(function () {
if ($('.menuitem').text().trim() === "Button 2"){
if ($('[is-checked="true"]'))
$('.element').css('display', 'block');
if ($('[is-checked="false"]'))
$('.element').css('display', 'none'); }
});
Here's a JSFIDDLE, of what I have:
$('.menuitem').click(function() {
console.log($(this).text().trim())
if ($(this).text().trim() === "Button 2") {
if ($(this).attr('is-checked') == 'true') {
$('.element').css('display', 'block');
} else {
$('.element').css('display', 'none');
}
}
});
.items {
height: 30px;
margin-bottom: 5px;
}
.menuitem {
float: left;
margin-right: 10px;
border: 1px solid;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="items">
<div class="menuitem" is-checked="true">
<div class="ytp-menuitem-label">Button 1</div>
</div>
<div class="menuitem" is-checked="false">
<div class="ytp-menuitem-label">Button 2</div>
</div>
</div>
<div class="element">some content</div>
<div class="element">some more content</div>
<div class="element">even more content</div>
Use $(this).attr('is-checked') to get the value
Also use $(this).text().trim() to get the text of clicked element
You've got it a tad wrong, your if statement isn't actually looking at the element which was clicked. Try something along these lines:
$('.menuitem').click(function () {
// $(this) is a reference to the element which was clicked
if ($(this).attr('is-checked') == "true")
$('.element').css('display', 'block');
if ($(this).attr('is-checked') == "false")
$('.element').css('display', 'none');
});

Categories

Resources