I get undefined error using pure javascript in my code - javascript

I am trying to add a material ripple effect to an element using pure javascript using the code below. The problem is that the effect works only for the first click.
If I try to click the button again, I get the message Uncaught TypeError: circle is undefined on my console.
function createRipple(event) {
const target = event.currentTarget;
const circle = target.classList.add("ripple");
const ripple = circle.getElementsByClassName("ripple")[0];
if (ripple) {
ripple.remove();
}
}
const buttons = document.getElementsByClassName("my-ripple");
for (const button of buttons) {
button.addEventListener("click", createRipple);
}
.my-ripple {
position: relative;
overflow: hidden;
display: inline-block;
width: auto;
padding: 1.2rem;
font-family: sans;
cursor: pointer;
border-radius: 10px;
}
.ripple::after {
content: "";
position: absolute;
border-radius: 50%;
transform: scale(0);
animation: ripple 600ms linear;
background-color: rgba(0, 0, 0, 0.5);
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
width: 100px;
height: 100px;
}
#keyframes ripple {
to {
transform: scale(4);
opacity: 0;
}
}
<div class="my-ripple">Click me</div>

classList does not return an object. And you do not need it actually, because you already have the target instance, so fetching it again by class is not necessary. Instead just remove the class from it directly with a timeout:
function createRipple(event) {
const target = event.currentTarget;
target.classList.add("ripple");
setTimeout(function() {
target.classList.remove("ripple");
}, 600);
}

Related

re-setting Interval after clearInterval

So I have an Interval that activates a function function Seifenblasen_blasen() every 100ms. I stop this Interval or function with clear Interval by running function function Bouny_Ball() when clicking the Button Bounce.
Now when I click the Button Bubble again it should start generating Bubbles every 100ms. But it doesn't, as it was cleared AND is not in the function Seifenblasen_blasen() therefore it still is cleared. But neither putting it in the function Seifenblasen_blasen() or making a seperate function and calling it with the same button press makes a difference. This is where I need your Help.
Thanks in advance.
This is not the only problem tho. I will make separate questions for these but if you have time feel free to ask and i'll provide them in a comment. I need to wait 90 minutes after all.
whole code
Function Seifenblasen_blasen() with Interval:
function Seifenblasen_blasen(){
document.getElementById("screen2").style.display = "none";
document.getElementById("screen").style.display = "block";
const section = document.querySelector('#screen')
const createElement = document.createElement('spawn')
var size = Math.random() * 60;
createElement.style.width = 30 + size + 'px';
createElement.style.height = 30 + size + 'px';
createElement.style.left = Math.random() * innerWidth + "px";
section.appendChild(createElement);
setTimeout(() => {
createElement.remove()
},8000)
}
const Blaseninterval = setInterval(Seifenblasen_blasen, 100)
Resulting CSS of function Seifenblasen_blasen()
#screen {
width: 100%;
height: 90vh;
overflow: hidden;
background-image: linear-gradient(#008CBA, #030a19);
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
#screen spawn {
position: absolute;
bottom: -80px;
background: transparent;
border-radius: 50%;
pointer-events: none;
box-shadow: inset 0 0 10px rgba(255, 255, 255, 0.5);
animation: animate 4s linear infinite;
}
#screen spawn:before {
content: '';
position: absolute;
width: 100%;
height: 100%;
transform: scale(0.25) translate(-70%, -70%);
background: radial-gradient(#fff, transparent);
opacity: 0.6;
border-radius: 50%;
}
#keyframes animate {
0% {
transform: translateY(0%);
opacity: 1;
}
99% {
opacity: 1;
}
100% {
transform: translateY(-2000%);
opacity: 0;
}
}
#screen span {
margin-top: 700px;
font-size: 1em;
color: #333;
margin: 0 auto;
font-family: consolas;
background-color: #1F69FA;
border: none;
position: absolute;
}
clearence of Interval:
function Bouncy_Ball() {
clearInterval(Blaseninterval);
document.getElementById("screen").style.display = "none";
document.getElementById("screen2").style.display = "block";
}

Hiding/Showing CSS elements does not work?

THE WHOLE CODE IN JSFIDDLE
I have been struggling to effectively remove the code and css created in the function Seifenblasen_blasen()
function Seifenblasen_blasen(){
btn1.style.display = 'none';
document.getElementById("text").innerHTML="Bubble"
const section = document.querySelector('section')
const createElement = document.createElement('spawn')
var size = Math.random() * 60;
createElement.style.width = 30 + size + 'px';
createElement.style.height = 30 + size + 'px';
createElement.style.left = Math.random() * innerWidth + "px";
section.appendChild(createElement);
setTimeout(() => {
createElement.remove()
},8000)
}
const Blaseninterval = setInterval(Seifenblasen_blasen, 100)
created CSS:
section {
width: 100%;
height: 100vh;
overflow: hidden;
background: #1F69FA;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
section.text{
font-size: 10em;
color: #333;
margin: 0 auto;
text-align: center;
font-family: consolas;
background-color:#1F69FA;
pointer-events: none;
border: none;
}
section spawn {
position: absolute;
bottom: -80px;
background: transparent;
border-radius: 50%;
pointer-events: none;
box-shadow: inset 0 0 10px rgba(255, 255, 255, 0.5);
animation: animate 4s linear infinite;
}
section spawn:before {
content: '';
position: absolute;
width: 100%;
height: 100%;
transform: scale(0.25) translate(-70%, -70%);
background: radial-gradient(#fff, transparent);
opacity: 0.6;
border-radius: 50%;
}
#keyframes animate {
0% {
transform: translateY(0%);
opacity: 1;
}
99% {
opacity: 1;
}
100% {
transform: translateY(-2000%);
opacity: 0;
}
section span {
margin-top: 700px;
font-size: 1em;
color: #333;
margin: 0 auto;
font-family: consolas;
background-color: #1F69FA;
border: none;
position: absolute;
}
HTML:
<section id="section">
<div class="content">
<button id="btn"></button>
<button id="btn1"></button>
</div>
</section>
to then execute the next function function next(). This removal is needed because when I don't remove the elements from the first function the second wont work. I could just do document.head.innerHTML = "" but that would then also remove the css needed for the button appearing in the next function. So then I tried to make variables with const
const btn = document.getElementById('text');
const btn1 = document.getElementById('text1');
const section = document.querySelector('section')
// in function Seifenblasen_blasen()
btn1.style.display = 'none';
// in function next()
section.style.display = 'none';
btn.style.display = 'none';
btn1.style.display = 'block';
to hide and show only parts of the css without removing the css entirely to keep the styling intact, but now nothing works anymore.(the button on the next Screen doesn't show up at all and the first button does not contain any styling) My endgoal is that I can essentially switch between two screens one showing the bubbles and one the bouncy balls and when I click on the button it goes on. (for example start is bubbles. I click -> Bounce, click again -> back to Bubbles and so on)

HTMLDivElement resizing inconsistent after WebpackDevServer build

I have a custom web component that I am trying to make which looks like this
But it looks like this after I reload the page
Notice the thin white div at the very bottom of each image.
I notice that I get the desired result (the fist image) immediately following a Webpack build triggered by saving this component's javascript file. Each time I reload the page, the second image is rendered on screen. What causes this behavior? I will attach the pertinent parts of my code below. (The styling for the large yellow and white components is done for privacy)
FeaturedProjectCard.js
const template = document.createElement('template')
template.innerHTML = `
<style>
.bottomDivider {
position: absolute;
bottom: 0;
width: 75%;
height: 1px;
margin: 0;
background-color: white;
}
.container {
position: relative;
width: 1000px;
isolation: isolate;
}
.description {
border-radius: 10px;
padding: 25px;
color: white;
background-color: white;
}
.linksContainer {
display: flex;
}
.linksContainer > a {
width: 20px;
padding: 10px;
color: white;
transition: color 0.5s;
}
.linksContainer > a:first-child {
padding-left: 0;
}
.linksContainer > a:hover {
color: yellow;
}
.projDesc {
width: 50%;
display: flex;
flex-direction: column;
pointer-events: none;
}
.projDesc > * {
width: fit-content;
pointer-events: auto;
}
.projImage {
position: absolute;
top: 50%;
right: 0;
height: 300px;
transform: translateY(-50%);
background-color: yellow;
border-radius: 5px;
z-index: -1;
}
.projImage > img {
height: inherit;
border-radius: inherit;
filter: grayscale(100%);
-webkit-filter: grayscale(100%);
opacity: 0;
transition: opacity 0.5s, filter 0.5s, -webkit-filter 0.5s;
}
.projImage > img:hover {
opacity: 1;
filter: grayscale(0%);
-webkit-filter: grayscale(0%);
}
.projectHeading {
margin: 10px 0;
color: yellow;
font-size: 12pt;
}
.projectName {
display: inline;
margin: 15px 0;
font-size: 21pt;
color: white;
}
.softwareContainer {
margin: 25px 0 10px 0;
color: white;
}
.softwareContainer > span:not(:last-child) {
padding-right: 30px;
}
</style>
<div class="container">
<div class="projDesc">
<span class="projectHeading">Recent Project</span>
<span class="projectName"></span>
<div class="description"></div>
<div class="softwareContainer"></div>
<div class="linksContainer"></div>
</div>
<div class="projImage">
<img>
</div>
<p class="bottomDivider"></p>
</div>
`
class FeaturedProjectCard extends HTMLElement {
constructor() {
super()
//Enable shadow DOM
this.attachShadow({ mode: 'open' })
this.shadowRoot.appendChild(template.content.cloneNode(true))
//Insert project image
this.shadowRoot.querySelector('img').src = this.getAttribute('image')
//Insert project heading
this.shadowRoot.querySelector('.projectName').textContent = this.getAttribute('heading')
//Insert project description
this.shadowRoot.querySelector('.description').innerHTML = //Get description text
//Insert software array
const softwareItems = //Get items
if(softwareItems) {
const softwareContainer = this.shadowRoot.querySelector('.softwareContainer')
for(let i = 0; i < softwareItems.length; i++)
softwareContainer.innerHTML += `<span>${softwareItems[i].textContent}</span>`
}
//Insert link array
const links = //Get links
if(links) {
const linksContainer = this.shadowRoot.querySelector('.linksContainer')
for(let i = 0; i < links.length; i++) {
linksContainer.innerHTML += `<a target="_blank" href="${links[i].getAttribute('target')}">${links[i].innerHTML}</a>`
}
}
//Handle reverse attribute
if(this.hasAttribute('reversed')) {
this.shadowRoot.querySelector('.bottomDivider').style.right = 0;
this.shadowRoot.lastElementChild.style.height = `${this.shadowRoot.lastElementChild.offsetHeight}px`
const projDesc = this.shadowRoot.querySelector('.projDesc')
const projImage = this.shadowRoot.querySelector('.projImage')
const softwareItems = Array.from(this.shadowRoot.querySelectorAll('.softwareContainer > span'))
projDesc.style.position = 'absolute'
projDesc.style.right = '0'
projDesc.style.left = 'auto'
projImage.style.left = '0'
projImage.style.right = 'auto'
projDesc.style.alignItems = 'flex-end'
softwareItems.splice(0, 1)[0].style.padding = '0'
const padding = getComputedStyle(softwareItems[0]).getPropertyValue('padding-right')
softwareItems.forEach(item => {
item.style.paddingLeft = padding
item.style.paddingRight = '0'
})
}
//Clear markup
this.innerHTML = null
}
}
window.customElements.define('featured-project-card', FeaturedProjectCard)
I use these component in HTML with the following syntax.
<featured-project-card class="" reversed image="/something.png" heading="Heading">
I think that the root cause of this behavior is the inclusion of the optional 'reversed' attribute. The other components that don't use this attribute are not affected by this issue since div.projDesc has position: static for those instances. This allows the div.container to resize. These images show the only component where this attribute is used. I will end this post with one final image of a component without the 'reversed' attribute for reference. In essence, I achieve the reverse effect by setting the div.projDesc properties position, right, and left to absolute, 0, and auto respectively. Consequently, I had to set the div.container height equal to what it was prior to these changes. Otherwise the element would not size correcly since position: absolute is being used on the only child with position: static
I used a ResizeObserver to see if the div.projDesc was resizing itself more than once and indeed it was. To wrap up, the 'reversed' div.projDesc is resizing itself strangely (likely because of how the 'reverse' attribute is handled) as opposed to non 'reversed' elements. I am aware that there may be an easier way to solve this problem and I am open to suggestions, however, I would like to pin down the source of this behavior in hopes of gaining a better understanding of the nuances of HTML, CSS, & JS. I am more than happy to clarify myself for anyone that is willing to lend a hand. Thank you in advance!
Non reversed component

Unable to achieve 60fps animations

I REALLY want to achieve 60fps animations. Specifically, on my input elements on the focus event. The highest (according to Chrome Developer Tools) fps I can achieve is about 18fps.
I am using everything that is said to be best practice: window.requestAnimationFrame in my JavaScript, will-change in my css, and i'm using transforms for the actual animations. Even with all of these set in place, my animations aren't near 60fps.
var form = {};
function addActive(element) {
element.highlightElement.classList.add("input-highlight-active");
}
function removeActive(element) {
element.highlightElement.classList.remove("input-highlight-active");
}
// loops through the entire object removing "active" class on all elements except fo rthe element that is the target.
function setNewState(element, id, obj) {
for (var key in obj) {
if (id === key) {
window.requestAnimationFrame(() => addActive(element));
} else {
removeActive(obj[key]);
}
}
}
// Captures the event.target.id and corresponding object to be passed to setNewState function
function handleEvent(e) {
var active = form[e.target.id];
var activeId = e.target.id;
setNewState(active, activeId, form);
}
// Adds focus event listener to html elements
function addEvent() {
var inputElements = document.querySelectorAll('.input-wrapper > input');
inputElements = Array.from(inputElements);
inputElements.map(el => el.addEventListener('focus', (e) => handleEvent(e)));
}
// Creates object using input id as object key
function init() {
var temp = {};
var inputElements = document.querySelectorAll('.input-wrapper > input');
for (var i = 0; i < inputElements.length; i++) {
temp[inputElements[i].id] = {
highlightElement: inputElements[i].nextElementSibling,
active: false
};
}
return temp;
}
form = init();
addEvent();
body {
background-color: #121217;
}
.input-wrapper {
position: relative;
width: 60%;
margin: 0px auto 40px;
text-align: left;
}
.input-label {
position: relative;
text-align: left;
font-size: 18px;
font-weight: 300;
letter-spacing: 0.012em;
color: #eee;
}
input {
appearance: none;
-webkit-appearance: none;
position: relative;
width: 100%;
margin: 8px auto 0;
letter-spacing: 0.012em;
font-size: 18px;
color: #fafafa;
background-color: #121217;
border: 0px;
transform-origin: left;
border-bottom: 1px solid #fafafa;
}
input:focus {
outline: none;
}
.input-highlight {
will-change: transform;
position: absolute;
top: 99%;
width: 101%;
height: 2px;
background-color: #006daa;
z-index: 1;
transform-origin: left;
transform: scaleX(0);
transition: all 0.12s linear;
}
.input-highlight-active {
will-change: transform;
transform: scaleX(1);
transition: all 0.12s linear;
}
<div class="input-wrapper">
<div class="input-label">Full name</div>
<input type="text" id="fullName">
<div class="input-highlight"></div>
</div>
At the end of the day, I am sure i'm obsessing over something most won't notice. Ultimately, I just want to understand. Even if you tell me i've done all I can.
In the code you provided, you are using CSS animations, just by applying the extra class. There's no need to call requestAnimationFrame because it's designed to be called multiple times via the callback.
Since you took advantage of CSS animations you only need to add the class that changes the scale ONCE on focus, then you can remove it on blur:
.input-highlight-active {
transform: scaleX(1);
}
Because the input already has a class where the transition value specifies it will animate all properties (that it's able to animate), you only need to specify the property change that's animated.
Demo

React how to handle resize of top border in a component

Recently I created my tabbed drawer component using React, I would like to add another feature to make the drawer resizable dragging the top border up or down.
I understand that I can set the height in the component state, create a function to handle the event and when the this.state.height is change React will render again the component to the right height.
I understand that I can handle this with JQuery using the resizable function but if possible I would avoid to interact directly with the DOM since this is what React aims to do.
I started to code in JS few weeks ago and I am missing the points below:
how can I handle or create an event in the top border of my div container id="drawer"?
how can I make this event return a value that indicates where the mouse stopped in term of height to get a new value to call setStatus and render my component with the right height one more time?
Below my code:
define(function (require) {
var React = require('react');
var DrawerButton = require('./DrawerButton');
require('./TabbedDrawer.less');
class TabbedDrawer extends React.Component {
constructor(props) {
super(props);
this.state = {
drawerOpened: false,
buttonSelected: null,
drawerHeight: 0
}
this.openDrawer = this.openDrawer.bind(this);
this.renderMyLabels = this.renderMyLabels.bind(this);
this.resizeDrawer = this.resizeDrawer.bind(this);
}
renderMyLabels() {
var renderedLabels = this.props.labels.map(function(label, _key) {
return (
<DrawerButton
functionDrawer={this.openDrawer}
labelKey={_key}
buttonSelected={this.state.buttonSelected}
drawerOpened={this.state.drawerOpened}>
{label}
</DrawerButton>
);
}, this);
return renderedLabels;
}
openDrawer(buttonClicked) {
if(this.state.drawerOpened && (buttonClicked == this.state.buttonSelected)) {
this.setState({buttonSelected: null,
drawerOpened: !this.state.drawerOpened});
} else if(this.state.drawerOpened && (buttonClicked != this.state.buttonSelected)) {
this.setState({buttonSelected: buttonClicked});
} else {
this.setState({buttonSelected: buttonClicked,
drawerOpened: !this.state.drawerOpened});
}
}
render() {
const ElementToRender = (this.state.buttonSelected !== null) ? this.props.children[this.state.buttonSelected] : null;
const myElement = (ElementToRender !== null) ? <ElementToRender /> : "";
const drawerStyle = this.state.drawerOpened ? {display: 'block'} : {display: 'none'};
const tabStyle = this.state.drawerOpened ? {bottom: '250px'} : {bottom: '0px'};
return (
<div id="testDrawer">
<span id="tabber" style={tabStyle}>
{this.renderMyLabels()}
</span>
<div id="drawer" style={drawerStyle}>
<div className="topLine" >
</div>
{myElement}
</div>
</div>
);
}
}
return TabbedDrawer;
});
#import "./../../../../style/less/components/colors";
#-webkit-keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
#keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
#geppettoDrawer {
display: inline-block;
}
#tabber {
-webkit-animation: fadeIn 1s;
animation: fadeIn 1s;
border-bottom: 0.5px solid rgb(252, 99, 32);
width: 100%;
display: block;
margin-top: 0px;
text-decoration: none;
left: 0;
bottom: 0;
position: absolute;
background: transparent;
}
#tabButton {
color: #primary_color;
margin: 0 auto;
margin-bottom: 26px;
position: relative;
border-color: rgb(252, 99, 32);
border: 0.5px;
border-bottom: 0px;
border-style: solid;
box-shadow: none;
text-shadow: none;
width: 140px;
height: 35px;
padding: 7px 20px;
text-align: center;
display: inline-block;
cursor: pointer!important;
background: rgba(50, 50, 53, 0.8);
}
#drawer {
-webkit-animation: fadeIn 1s;
animation: fadeIn 1s;
height: 250px;
width: 100%;
background-color: black;
color: white;
position: fixed;
bottom: 0px;
left: 0px;
display: none;
transition: opacity 1s ease-out;
-webkit-animation: fadeIn 1s;
animation: fadeIn 1s;
background: rgba(50, 50, 53, 0.8);
}
I would have a look at the available events here: https://reactjs.org/docs/events.html
I would also view this other thread: Recommended way of making React component/div draggable

Categories

Resources