After hiding parts of the div remains - javascript

A colleague of mine created a template with angularjs. It consists of menus, that can be closed. This is achieved by simple jQuery. However after clicking the close button the lower part of the menu-div remains. If the mouse is moved it disappears. I can't reproduce the error in a js fiddle. Why do parts still remain, how to fix this?
HTML
<div class="menu">
<button class="close"> X close this </button>
</div>
CSS
.menu{
width: 100px;
height: 200px;
padding: 20px;
background: lightgrey;
}
.hide{
display: none;
}
JS
$('body').on('click', '.close', function(){
$(this).closest('.menu').addClass('hide');
});
/// also does not work
$('body').on('click', '.close', function(){
$(this).closest('.menu').hide();
});

First of all you are using angularjs, and you cannot use jQuery as on standard web sites.
you have this JS:
$('body').on('click', '.close', function(){
$(this).closest('.menu').addClass('hide');
});
but in moment when this script is executed there is no HTML rendered to page, so this script is usless.
You need to create a custom directive in order to make this work.
.directive('ngHideCustom', function () {
return function (scope, elm, attrs) {
$('.close', elm).click(function () {
$(this).parent().hide();
});
}
})
and you need to change the html to call this directive
<div class="menu" ng-hide-custom>
<button class="close"> X close this </button>
</div>
this way your script will be applied only when this part of HTML is rendered to page.

Related

Can't hide other elements while clicking on another

I'm trying to make a toggle which works, but every element I click on creates a stack of these showed elements. Instead I'm trying to hide everything and display only element that I clicked on. Now I can only hide it when I click on the same element twice, which is not what I want. I want to click on one and hide previous ones that were showing.
.totalpoll-choice-image-2 is a bunch of images that always has to be shown. They are what the user clicks on to display hidden description under each image. That description shows up when I click on .totalpoll-choice-image-2. There are 5 images with that class. The next image I click on, I want to hide the previous description box.
My code:
jQuery(document).ready(function() {
var element = document.getElementsByClassName("totalpoll-choice-image-2");
var elements = Array.prototype.slice.call(Array.from( element ) );
console.log(elements);
jQuery(element).each(function(item) {
jQuery(this).unbind('click').click(function(e) {
e.stopPropagation();
var id = jQuery(this).attr("data-id");
console.log(this);
//jQuery("#" + id).css({"display": 'block !important'});
//document.getElementById(id).style.setProperty( 'display', 'block', 'important' );
var descriptionContainer = document.getElementById(id);
var thiss = jQuery(this);
console.log(thiss);
console.log(jQuery(descriptionContainer).not(thiss).hide());
jQuery(descriptionContainer).toggleClass("show");
});
})
})
You can attach event handlers to a group of DOM elements at once with jQuery. So in this case, mixing vanilla JS with jQuery isn't doing you any favors - though it is possible.
I threw together this little example of what it sounds like you're going for.
The script itself is very simple (shown below). The classes and IDs are different, but the idea should be the same:
// Assign click handlers to all items at once
$('.img').click(function(e){
// Turn off all the texts
$('.stuff').hide();
// Show the one you want
$('#' + $(e.target).data('id')).show();
})
https://codepen.io/meltingchocolate/pen/NyzKMp
You may also note that I extracted the ID from the data-id attribute using the .data() method, and attached the event listener with the .click() method. This is the typical way to apply event handlers across a group of jQuery objects.
From what I understood based on your comments you want to show only description of image that has been clicked.
Here is my solution
$('.container').on('click', 'img', function() {
$(this).closest('.container').find('.image-description').addClass('hidden');
$(this).siblings('p').removeClass('hidden');
});
https://jsfiddle.net/rtsj6r41/
Also please mind your jquery version, because unbind() is deprecated since 3.0
You can use event delegation so that you only add your event handler once to the parent of your images. This is usually the best method for keeping work the browser has to do down. Adding and removing classes is a clean method for show and hide, because you can see what is happening by looking at your html along with other benefits like being easily able to check if an item is visible with .hasClass().
jsfiddle: https://jsfiddle.net/0yL5zuab/17/
EXAMPLE HTML
< div class="main" >
<div class="image-parent">
<div class="image">
</div>
<div class="image-descr">
Some text. Some text. Some text.
</div>
</div>
<div class="image-parent">
<div class="image">
</div>
<div class="image-descr">
Some text. Some text. Some text.
</div>
</div>
<div class="image-parent">
<div class="image">
</div>
<div class="image-descr">
Some text. Some text. Some text.
</div>
</div>
<div class="clear">
</div>
</div>
EXAMPLE CSS
.image-parent{
height: 100px;
width: 200px;
float: left;
margin: 5px;
}
.image-parent .image{
background: blue;
height: 50%;
width: 100%;
}
.image-descr{
display: none;
height: 50%;
width: 100%;
}
.show-descr{
display: block;
}
.clear{
clear: both;
}
EXAMPLE JQUERY
$(".main").on("click", ".image-parent", ShowDescription);
function ShowDescription(e) {
var $parent = $(e.target).parent(".image-parent");
var $desc = $parent.find(".image-descr");
$(".image-descr").removeClass("show-descr");
$desc.addClass("show-descr");
}

Handle nestled ng-click's with "peek through" in Angularjs

I'm having a bit of trouble handling multiple, nestled, angularjs mousebutton directives.
I have a template that looks like this:
<div class="project-wrap">
<div class="workspace-wrap">
<div id="workspace" class="workspace"
oncontextmenu="return false;"
ng-mousedown="project.checkBtnDown($event)"
ng-mouseup="project.checkBtnUp($event)"
ng-mousemove="project.mouseMoved($event)">
</div>
</div>
<button class="logoutBtn" ng-click="project.logout()">
Logout
</button>
</div>
What checkBtnDown() does, is simply check which of the mousebuttons was pressed and then processes it.
The problem I'm having is, when the left mousebutton is pushed down on the "workspace" (within my ProjectCtrl's template), it places a SVG element inside the "workspace" div. This SVG element is bound with an custom angular directive, which has a ng-click on it's template.
So what's happening is, I create the SVG element as planned but, when I click on the portion of the SVG element that I want to call a function on scope. It's still calling checkBtnDown(), because the new SVG element is inside the project template.
How can I get the SVG element ng-click to "peek through" and not fire checkBtnDown() simultaneously?
Hi, i don't know if you meaning this or not..hope this helps you.
in fact you just need to detect if your mouse clicked or not, for that we need to something to detect this for second time.
var app = angular.module("app", []);
app.controller("ctrl", function ($scope) {
$scope.alreadyClicked = false;
$scope.action = function() {
console.log("action");
}
$scope.mousedown = function (event) {
if ($scope.alreadyClicked) {
$scope.action();
} else {
console.log("mousedown");
$scope.alreadyClicked = true;
}
}
});
.box {
position: relative;
background: #eee;
border: solid 1px #ccc;
float: left;
width: 100px;
height: 100px;
cursor:pointer
}
<!DOCTYPE html>
<html ng-app="app" ng-controller="ctrl">
<head>
<title></title>
</head>
<body>
<div class="box" ng-mousedown="mousedown($event)">
{{alreadyClicked ? "click to call action":"click to call mousedown"}}
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
</body>
</html>
What I decided to do using your suggestion Mayer,
"In fact you just need to detect if your mouse clicked or not, for that we need to [do] something to detect this for second time."
was to measure the maximum time between the first and second mouse-events, then use a setTimeout().
Here's some pseudo-code to illustrate my idea.
// First mouse-down event
if (firstEvent) {
var timerID = setTimeout(function() {
// handle first mouse-event
}, dTimeBetween);
}
// Second mouse-down event
if (secondEvent) {
clearTimeout(timerID);
function() {
// handle second mouse-event
}
}

Select <divs> within parent <div> using jQuery

I have a parent <div>, #amwcontentwrapper, which has a series of divs within it with their own classes and ids.
I want to use jQuery to select these child divs, and IF they have the class .amwhidden, do nothing, but if not, remove the .amwshown class and add the .amwhidden class.
This is what I have so far, but it is not working. I think it may be my selecting of the child divs within the parent.
Can anybody see any obvious problems? Thanks for your help.
if ($('#amwcontentwrapper > div').hasClass('amwhidden')){
} else {
$('#amwcontentwrapper > div').fadeIn(600, function(){
$('#amwcontentwrapper > div').removeClass('amwshown');
$('#amwcontentwrapper > div').addClass('amwhidden');
});
}
And here is the basic html that I am using:
<div class="amwshown" id="amwintro">
Intro Section, which should have the 'amwshown' class removed, and the
'amwhidden' class added, when the jQuery runs. Currently, this does not happen.
</div>
UPDATE: Using War10ck's solution in the comments below (i.e. $('#amwcontentwrapper > div.amwshown')) I have managed to get the classes changing as I wished. However, those which have had the .amwshown class removed and .amwhidden class added still show on the page, despite the CSS looking like this:
.amwhidden {
display:none;
}
.amwshown {
display:block;
}
Looking at the Dev Tools, it seems that, when the jQuery is run (on a click event) the classes are changing, but any classes which are having the .amwshown class added (thus displaying them on the page) are also having the a <style> tag added to them which makes them display:block;
When I then press another button, which should hide the aformentioned <div> to make way for another one, the class is being changed to .amwhidden, but that <style> tag is not being deleted, so even though it has the .amwhidden class, it is still on the page.
I've created a JSFiddle here, if anybody still wants to help!
`
$(document).ready(function() {
$('#buybutton').click(function() {
$('#amwcontentwrapper > div.amwshown').fadeIn(600, function() {
$(this).removeClass('amwshown').addClass('amwhidden');
});
if ($('#amwbuy').hasClass('amwshown')) {} else {
$('#amwbuy').fadeIn(600, function() {
$('#amwbuy').removeClass('amwhidden');
$('#amwbuy').addClass('amwshown');
});
}
});
$('#phdbutton').click(function() {
$('#amwcontentwrapper > div.amwshown').fadeIn(600, function() {
$(this).removeClass('amwshown').addClass('amwhidden');
});
if ($('#amwphd').hasClass('amwshown')) {} else {
$('#amwphd').fadeIn(600, function() {
$('#amwphd').removeClass('amwhidden');
$('#amwphd').addClass('amwshown');
});
}
});
});
#sidebar {
position: absolute;
left: 1%;
top: 1%;
font-size: 5em;
color: #000000;
width: 10%;
display: block;
background-color: red;
}
#amwcontentwrapper {
position: absolute;
left: 20%;
top: 5%;
}
.amwshown {
display: block;
}
.amwhidden {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="amwsidebar">
<span class="sidebarbutton" id="phdbutton">PhD Button</span>
<br />
<br />
<span class="sidebarbutton" id="buybutton">Buy Button</span>
</div>
<div id="amwcontentwrapper">
<div class="amwshown" id="amwintro">
<p>An intro section to welcome the visitor. Disappears when one of the other sections is clicked.</p>
<br />
<br />
</div>
<div class="amwhidden" id="amwbuy">
Buy Section
</div>
<div class="amwhidden" id="amwphd">
PhD Section
</div>
</div>
`
You can use not to remove the elements you do not want, like this:
$('#amwcontentwrapper > div').not('.amwhidden')
.removeClass('amwshown')
.addClass('amwhidden');
And work with that.
Try this
$(document).ready(function() {
$("#amwcontentwrapper").children().each(function(elem, x) {
if ($(x).attr("class") == "amwhidden") {
alert($(x).attr("class"));
$(x).removeClass("amwhidden").addClass("amwshow");
alert($(x).attr("class"));
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div id="amwcontentwrapper">
<div class="amwhidden"></div>
<div></div>
<div></div>
</div>
You can try each as follow,
$("#amwcontentwrapper div").each(function(){
if($(this).hasClass('amwhidden'))
//DO something
else
//DO something
});
Thank you for all help, it has prompted some brainstorming which has solved this issue.
Instead of adding the .amwhidden class and removing the .amwhidden class using jQuery, I have just created a .amwsection class, which all the sections belong to which has an initial display value of none. So far, so good; all of the sections are not there when you load up the page.
Then I use the .css jQuery function to change the display:none to display:block when the corresponding button is clicked, and changing all other .amwsections to display:none. This works just fine, but the effect is quite abrupt; there is no fading in, as you would get if you used the .animate function. .animate, however, does not work with the display value.
.fadeOut and .fadeIn to the rescue! By wrapping the .css change in these, I can create a fading in/out effect and can still use the display value.
Here is one example of this code.
The #buybutton is the button to be pressed.
#amwintro is just something which appears when the page loads - it will now be set to display:none if this is the first button pressed.
The .amwsection are all of the hidden sections. This portion of the code just resets all of them. This and the #amwintro section happen very quickly (1/100th of a second) to keep response time good.
The #amwbuy is the specific section that I want to reveal. As you can see, this fades in over a longer period.
Currently only tested in Chrome, but I think I've got it!
$(document).ready(function () {
$('#buybutton').click(function() {
$('#amwintro').fadeOut(1, function() {
$(this).css({
display:'none',
});
});
$('.amwsection').fadeOut(1, function() {
$(this).css({
display:'none',
});
});
$('#amwbuy').fadeIn(600, function() {
$(this).css({
display:'block',
});
});
});
});

CLose Button doesn't appear on magnific-popup

This should be simple .... However....
I've tried almost everything to get the Close (X) Button to appear on the magnific popup. But it doesn't happen. There's no escape from the popup page except for the Back option. Here's what I've got:
.white-popup {
position: relative;
background: #FFF;
padding: 20px;
width: auto;
max-width: 500px;
margin: 20px auto;
}
and
<div class="popup-modal">
<img src="img/paintings/acrylic-trulkhor-1.png">
</div>
<div id="test-modal" class="mfp-hide white-popup">
<p><button class="closePopup">Close</button></p>
</div>
<script type="text/javascript">
$('.popup-modal').magnificPopup({
type: 'inline',
modal: false,
});
$(document).on('click', '.closePopup', function (e)
{
e.preventDefault();
$.magnificPopup.close();
});
</script>
</div>
Any ideas?
Thanks.
Here is a working example: https://jsfiddle.net/0rd5dc3v/2/
There are a few things I changed:
// Change the html link to the popup id, not the image url
<div class="popup-modal">
<a class="popup-modal-link" href="#test-modal"><img src="img/paintings/acrylic-trulkhor-1.png"></a>
</div>
// Call magnificPopup on the <a> element, not the outer div
$('.popup-modal-link').magnificPopup({
type: 'inline',
// Hide the builtin close button so we can use a custom close button
showCloseBtn: false
});
The button is white in color by default. To make it visible set its CSS property to black or any color that is visible on a white background.
.mfp-close {
color : black;
}
A simple workaround is to include the closeMarkup property in the object you init Magnific Popup with, and adding in a custom class to that markup.
Then, add that named custom class from your markup to your CSS with display set to something other than 'none', and marked !important.
Within the Magnific Popus JS:
closeMarkup:"<button title='%title%' type='button' class='mfp-close myDisplayOverride'>×</button>"
CSS:
.myDisplayOverride{
display:block !important
}
5 years late to the party!
I had the same issue as you did: when inline was set to true, the close button was not there.
You need to add the closeBtnInside: true configuration option in order to make the button visible.
So in your case:
$('.popup-modal').magnificPopup({
type: 'inline',
modal: false,
closeBtnInside: true
});
Just keep in mind that if you have custom markup for you close button, you need to add a tiny bit of CSS magic to make it work on click.
My custom button markup looks like this:
closeMarkup: '<button type="button" class="mfp-close"><i class="far fa-times"></i></button>'
And when you click on the <i class="far"> element, nothing happens.
So you need to add
.mfp-close i {
pointer-events: none;
}
because magnificPopup has the click handler bound to the button element but not its children...

Javascript addClass removeClass not working as desired

When I click on the icon, I want it to be switched on/off.
In my html file I have:
<div class="startSharing"></div>
And in my js:
$('.startSharing').click(function() {
$(this).removeClass('startSharing');
$(this).addClass('stopSharing');
});
$('.stopSharing').click(function() {
$(this).removeClass('stopSharing');
$(this).addClass('startSharing');
});
It works fine when switching from on to off - but I don't understand why it still goes into "startSharing" section when it is turned off.
Thank you for help.
In this case, you're setting the handlers to the particular elements. Once they're set - they're set, regardless of the selector changing.
You could just define it on the .startSharing element, if they all start like that. Then, you could use .toggleClass() to easily switch them on/off:
$('.startSharing').click(function() {
$(this).toggleClass('startSharing stopSharing');
});
You may also delegate the click event like this:
$('body').on('click', '.startSharing', function() {
$(this).removeClass('startSharing').addClass('stopSharing');
});
$('body').on('click', '.stopSharing', function() {
$(this).removeClass('stopSharing').addClass('startSharing');
});
Doing it this way will also allow dynamically-generated to trigger events. In your case, .stopSharing was generated dynamically.
use event delegation
$('#container').on('click',".startSharing,.stopSharing",function(){
$(this).toggleClass('startSharing').toggleClass('stopSharing');
});
#container div {
width: 250px;
height: 100px;
}
.startSharing {
background-color: green;
}
.startSharing::after {
content: "start sharing";
}
.stopSharing {
background-color: red;
}
.stopSharing::after {
content: "stop sharing";
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
<div class="startSharing"></div>
</div>

Categories