access to shadow dom properties - javascript

so here is my script code
class Pop extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
let currDoc = document.currentScript.ownerDocument;
let template = currDoc.querySelector('#pop-up');
let tmplNode = document.importNode(template.content, true);
let shadowRoot = this.createShadowRoot();
shadowRoot.appendChild(tmplNode);
shadowRoot.querySelector("#content").innerHTML = this.innerHTML;
}
}
window.customElements.define("pop-up", Pop);
and here is my template
<template id="pop-up">
<style>
* {
padding: 0;
margin: 0;
}
.btn {
//styling
}
.btn:hover {
//styling
}
#box{
//styling
display: none;
}
#box h1{
//styling
}
</style>
<div id="box">
<h1> Your Shopping Cart</h1>
<text id="content"> </text>
<button class="btn" onclick="close()"> Close </button>
</div>
</template>
and in my index file i have this
<button class="btn" onclick="pop()">Show Pop</button>
<pop-up id="pop"> pop-up box</pop-up>
<script>
function pop(){
document.getElementById("pop").style.display = "block";
}
</script>
I am trying to do a pop-up box. And when i click on the "Show Pop" button i want to change the display property from style to "block" from "none". But for some reason it doesn't work. Im new to this shadow dom elemets and i can't really figure it out.

It is hard to explain everything in this answer, but the following code will give you an overview of how the solution might look like.
MDN, as usual, has the perfect intro for web components and shadow doms here
class Pop extends HTMLElement {
constructor() {
// Always call super first in constructor
super();
let template = document.getElementById('pop-up');
let templateContent = template.content;
// Create a shadow root
const shadowRoot = this.attachShadow({ mode: 'open' })
.appendChild(templateContent.cloneNode(true));
// attach close listener
this.shadowRoot.querySelector('.btn').addEventListener('click', this.close.bind(this));
}
// close pop-up
close() {
this.style.display = 'none';
}
// open pop-up
open() {
this.style.display = 'block';
}
}
window.customElements.define("pop-up", Pop);
function pop() {
// notice we are using the open method here
document.getElementById("pop").open();
}
<template id="pop-up">
<style>
:host {
display: none;
}
* {
padding: 0;
margin: 0;
}
.btn {
//styling
}
.btn:hover {
//styling
}
#box {
//styling
display: none;
}
#box h1 {
//styling
}
</style>
<div id="box">
<h1> Your Shopping Cart</h1>
<!-- Notice we are using slots -->
<slot> </slot>
<button class="btn"> Close </button>
</div>
</template>
<button class="btn" onclick="pop()">Show Pop</button>
<pop-up id="pop"> pop-up box </pop-up>

Related

Toggle show/hide functions between multiple divs

I have a page on my site which has 3 separate 'hidden' divs. Each with it's own 'show/hide' button.
Currently... each div and button set functions independently.
Therefore... if all divs are shown (open) at the same time, they stack according to their respective order.
Instead of that, I would rather restrict the function a bit, so that only div can be shown (open) at a time.
Example: If Div 1 is shown, and the user then clicks the Div 2 (or Dive 3) button, Div 1 (or which ever div is open at the time, will close.
I am not sure how to adjust my code to make that all work together. I have tried a few ideas, but they were all duds. So I posted a generic 'independent' version below.
function show_Div_1() {
var div1 = document.getElementById("Div_1");
if (div1.style.display === "none") {
div1.style.display = "block";
} else {
div1.style.display = "none";
}
}
function show_Div_2() {
var div2 = document.getElementById("Div_2");
if (div2.style.display === "none") {
div2.style.display = "block";
} else {
div2.style.display = "none";
}
}
function show_Div_3() {
var div3 = document.getElementById("Div_3");
if (div3.style.display === "none") {
div3.style.display = "block";
} else {
div3.style.display = "none";
}
}
.div {
width: 270px;
height: 30px;
padding-left: 10px;
}
<button type="button" onclick="show_Div_1()">Div 1 - Red</button>
<button type="button" onclick="show_Div_2()" style="margin-left: 4px">Div 2 - Blue</button>
<button type="button" onclick="show_Div_3()" style="margin-left: 4px">Div 3 - Green</button>
<div id="Div_1" class="div" style="background-color:red; display: none;"></div>
<div id="Div_2" class="div" style="background-color:blue; display: none;"></div>
<div id="Div_3" class="div" style="background-color:green; display: none;"></div>
I would suggest using data attributes for a toggle. Why? you can use CSS for them and you can use more than just a toggle - multiple "values".
Here in this example I do your "click" but also added a double click on the button for a third value. Try some clicks and double clicks!
A bit of overkill perhaps but more than just "toggle" for example you could use this to show "states" of things like a stoplight or any number of things.
Use the grid display and move them by just adding a data attribute value and double click it to get it to go (using css) to some grid-area:, things like that.
const hideValues = {
hide: "hidden",
show: "showme",
double: "dblclick"
};
function dblClickHander(event) {
const targetSelecor = event.target.dataset.target;
const target = document.querySelector(targetSelecor);
const action = target.dataset.hideme == hideValues.double ? hideValues.hide : hideValues.double;
const toggleTargets = document.querySelectorAll('.toggle-target');
toggleTargets.forEach(el => {
el.dataset.hideme = hideValues.hide;
});
target.dataset.hideme = action;
}
function toggleEventHandler(event) {
const targetSelecor = event.target.dataset.target;
const target = document.querySelector(targetSelecor);
const showHide = target.dataset.hideme == hideValues.hide ? hideValues.show : hideValues.hide;
const toggleTargets = document.querySelectorAll('.toggle-target');
toggleTargets.forEach(el => {
el.dataset.hideme = hideValues.hide;
});
target.dataset.hideme = showHide;
}
/* set up event handlers on the buttons */
const options = {
capture: true
};
/* we do this first to prevent the click from happening */
const toggleButtons = document.querySelectorAll('.toggle-button');
toggleButtons.forEach(el => {
el.addEventListener('dblclick', dblClickHander, options);
});
toggleButtons.forEach(el => {
el.addEventListener('click', toggleEventHandler, options)
});
.toggle-target {
width: 270px;
height: 30px;
padding-left: 10px;
}
.toggle-target[data-hideme="hidden"] {
display: none;
}
.toggle-target[data-hideme="showme"] {
display: block;
}
.toggle-target[data-hideme="dblclick"] {
display: block;
border: solid 2px green;
padding: 1rem;
opacity: 0.50;
}
.red-block {
background-color: red;
}
.blue-block {
background-color: blue;
}
.green-block {
background-color: green;
}
<button type="button" class="toggle-button" data-target=".red-block">Div 1 - Red</button>
<button type="button" class="toggle-button" data-target=".blue-block">Div 2 - Blue</button>
<button type="button" class="toggle-button" data-target=".green-block">Div 3 - Green</button>
<div class="toggle-target red-block" data-hideme="hidden">red</div>
<div class="toggle-target blue-block" data-hideme="hidden">blue</div>
<div class="toggle-target green-block" data-hideme="hidden">green</div>
This can be done in many ways. I think the best approach in your case could be
BUTTONS
<button type="button" onclick="show_div('Div_1')">Div 1 - Red</button>
<button type="button" onclick="show_div('Div_2')" style="margin-left: 4px">Div 2 - Blue</button>
<button type="button" onclick="show_div('Div_3')" style="margin-left: 4px">Div 3 - Green</button>
SCRIPT
function show_div(div_id) {
var thisDiv = document.querySelector('#'+div_id);
var thisState = thisDiv.style.display;
// close all in any cases
document.querySelectorAll('.div').forEach(function(el) {
el.style.display = "none";
});
// open this div only if it was closed
if (thisState == "none" ){
thisDiv.style.display = "block";
}
}

In JavaScript DOM is it possible to clone an entire button functionality to another?

I mean is it possible to connect an existing button with a newly created button that will work as the existing button?
Reference site: https://www.ninetypercent.com/products/sleeveless-gather-maxi-dress-c5?color=red
Please paste the below code to the browser console after opening the above link:
let title = document.querySelector(".product-details__name").textContent;
let price;
let oldPrice = document.querySelector(".product-details__old-price");
if (oldPrice) {
price = oldPrice.nextSibling.textContent.trim();
} else {
price = document.querySelector(".js-product-price").textContent;
}
let div = document.createElement("div");
let path = document.querySelector("header");
div.innerHTML = `
<div
id="sticky-nav"
style="position: fixed;
top:110px;
display: none;
padding: 0 10px;
justify-content: space-between;
align-items: center;
background-color:#e4e4e4;
width: 100vw;"
class="sticky-wrapper"
>
<div
style="width:80%; display: flex; justify-content: space-between; align-items:center"
class="sticky-text-wrapper"
>
<p style="margin: 0;" class="sticky-text">${title}</p>
<p style="margin: 0;" class="sticky-price">${price}</p>
</div>
<span style="width: 18%; display: flex; justify-content: space-around;" class="button"></span>
</div>`;
path.appendChild(div);
const sourceElement = document.querySelector(".js-product-details-submit-wrapper button");
const destination = document.querySelector(".button");
const copy = sourceElement.cloneNode(true);
destination.appendChild(copy);
window.addEventListener("scroll", () => {
const scrollPos = window.scrollY;
if (scrollPos > 1500) {
document.getElementById("sticky-nav").style.display = "flex";
} else {
document.getElementById("sticky-nav").style.display = "none";
}
});
I want to connect the sticky-nav button to the existing "Add to Bag" button and the functionality of both button will be the same. The same messaging as in control will appear on the PDP(Product details page) and basket icon quantity will increase. How can I do that?
Within the click-handler for the one button you could trigger the other, like so (names are made up of course):
stickyNavBtn.onclick = () => addToBagBtn.click();
You can create a function (in JS) and call it from both the original button (addToBagBtn in your case) and newly created button (stickyNavBtn in your case).
Like:-
/*JavaScript*/
function doSomething() {
alert("Replace with whatever task you like!");
}
var button = document.createElement("button");
button.innerText = "Newly Created Button";
button.onclick = function() {
doSomething();
}
document.getElementById("container").appendChild(button);
<!--HTML-->
<button id="button1" onclick="doSomething()">Original Button</button>
<br><br>
<div id="container">
<!--New button will be created here from JS-->
</div>

Hide pop-up by clicking outside it (problems with Philip Waltons solution)

I know the question of closing a pop-up by clicking outside of it has been asked before. I have a somewhat complex pop-up and the solution offered by Phillip Walton isn't working for me.
His code simply made my page blurry but stopped the popup from appearing.
$(document).on('click', function(event) {
if (!$(event.target).closest('.maincontainer').length) {
popup.classList.remove('popup--open');
popup.style.display = 'none';
popupAccessory.style.display = 'none';
popupAccessory.classList.remove('popup--accessory--open');
maincontainer.classList.remove('blurfilter');
}
});
I also tried:
window.addEventListener('click', function(event) {
if (event.target != popup) {
popup.classList.remove('popup--open');
popup.style.display = 'none';
popupAccessory.style.display = 'none';
popupAccessory.classList.remove('popup--accessory--open');
maincontainer.classList.remove('blurfilter');
}
}, true);
This closes the popup when I click anywhere, including on the popup itself. I want it to close only when I click on part of the screen that isn't the popup.
The code to open the popup:
function openpopup() {
popup.style.display = 'initial';
setTimeout(function(){
popup.classList.add('popup--open');
popup.style.boxShadow = '0 0 45px 2px white';
maincontainer.classList.add('blurfilter')}, 10);
for (let i = 0; i < listitems.length; i++ ) {
setTimeout(function() {
listitems[i].classList.add('visible');
}, 100);
}
}
I added the event listener to a button
popupOpenbtn.addEventListener('click', openpopup);
The HTML structure:-
<div class="maincontainer>
...all my page content...
</div>
<div class="popup">
...popup contents...
</div
I would suggest using only css classes to style your popup and use JS only to add, remove and toggle that class. Not sure how close to your working exercise is this fiddle but I've prepared this to show how the document/window click event can be checked to successfully open/close the popup window.
var popupOverlay = document.querySelector('#popup__overlay');
var popupOpenButton = document.querySelector('#popupOpenButton');
var popupCloseButton = document.querySelector('#popupCloseButton');
var mainContainer = document.querySelector('main');
function closestById(el, id) {
while (el.id != id) {
el = el.parentNode;
if (!el) {
return null;
}
}
return el;
}
popupOpenButton.addEventListener('click', function(event) {
popupOverlay.classList.toggle('isVisible');
});
popupCloseButton.addEventListener('click', function(event) {
popupOverlay.classList.toggle('isVisible');
});
mainContainer.addEventListener('click', function(event) {
if (popupOverlay.classList.contains('isVisible') && !closestById(event.target, 'popup__overlay') && event.target !== popupOpenButton) {
popupOverlay.classList.toggle('isVisible');
}
});
#popup__overlay {
display: none;
background-color: rgba(180, 180, 180, 0.5);
position: absolute;
top: 100px;
bottom: 100px;
left: 100px;
right: 100px;
z-index: 9999;
text-align: center;
}
#popup__overlay.isVisible {
display: block;
}
main {
height: 100vh;
}
<aside id="popup__overlay">
<div class="popup">
<h2>Popup title</h2>
<p>
Lorem ipsum
</p>
<button id="popupCloseButton">Close popup</button>
</div>
</aside>
<main>
<div class="buttonWrapper">
<button id="popupOpenButton">Open popup</button>
</div>
</main>

Toggle OnClick to dynamically change CSS

I have a button to show and hide certain part by calling CSS stylesheet change with onClick button. I want the same onclick to toggle in between hide and show. And it is hiding the content with .HeaderContainer {display:none;} but can I get help how to toggle it ?
I want same button if click again then it should override the .HeaderContainer with just {} ;
I have made the code like this to hide. I need how the same button can show this again.
<script type="text/javascript">
function loadToggleAction() {
var sheet = document.createElement('style')
sheet.innerHTML = ".HeaderContainer {display:none;}";
document.body.appendChild(sheet);
}
</script>
<form>
<input type="button" id="dxp" class="button" value="Hide top Pane" onclick='javascript: loadToggleAction();' />
</form>
You could do it like this:
var isHidden = false;
function loadToggleAction() {
var sheet = document.createElement('style')
if(!isHidden){
sheet.innerHTML = ".HeaderContainer {display:none;}";
}else{
sheet.innerHTML = ".HeaderContainer {display:block;}";
}
document.body.appendChild(sheet);
isHidden = !isHidden; //This will change the value to the opposite
}
Or like I would to it:
var isHidden = false;
function toggleVisibility() {
var div = document.getElementsByClassName("test")[0];
if(!isHidden){
div.style.display = "none";
}else{
div.style.display = "block";
}
isHidden = !isHidden;
}
.test {
display: block;
width: 100px;
height: 100px;
background: #ff0000;
}
<div class="test"></div>
<button onclick="toggleVisibility()">Click me</button>

Pure JS // Hide div when another divs class has been changed

Note: I can't use jQuery, only vanilla javascript
I'm not really fluent in pure JS. And this time I can't use any external resources (like jquery).
What I need:
If div1 class is active, hide text2
If div2 class is active, hide text1
I made it somehow to work, but my JS doesn't trigger when the class changes dynamic with another javascript code.
Code that triggers the active class
function activeClass(elem) {
var a = document.getElementsByClassName('item')
for (i = 0; i < a.length; i++) {
a[i].classList.remove('active')
}
elem.classList.add('active');
}
Code that should trigger hide/show when the class changes
if (document.querySelector(".text2").classList.contains("active")) {
document.getElementsByClassName('text1s')[0].style.visibility = 'hidden';
document.getElementsByClassName('text2s')[0].style.visibility = 'visible';
}
if (document.querySelector(".text1").classList.contains("active")) {
document.getElementsByClassName('text2s')[0].style.visibility = 'hidden';
document.getElementsByClassName('text1s')[0].style.visibility = 'visible';
}
What did I do wrong?
Codepen demo
Place your conditions inside click handler.
Add inline visibility style for inactive element
function activeClass(elem) {
var a = document.getElementsByClassName('item')
for (i = 0; i < a.length; i++) {
a[i].classList.remove('active')
}
elem.classList.add('active');
if (document.querySelector(".text2").classList.contains("active")) {
document.getElementsByClassName('text1s')[0].style.visibility = 'hidden';
document.getElementsByClassName('text2s')[0].style.visibility = 'visible';
}
if (document.querySelector(".text1").classList.contains("active")) {
document.getElementsByClassName('text2s')[0].style.visibility = 'hidden';
document.getElementsByClassName('text1s')[0].style.visibility = 'visible';
}
}
body {
margin: 3em;
}
.item {
cursor: pointer;
}
a {
padding: 10px;
}
.active {
color: red;
border: 1px solid red;
}
<a class="item text1" onclick="activeClass(this)">show text</a>
<a class="item text2 active" onclick="activeClass(this)">hide text</a>
<br>
<br>
<h1 class="text1s" style='visibility:hidden;'>TEXT 1</h1>
<h1 class="text2s">TEXT 2</h1>
Updated Codepen

Categories

Resources