I want to keep the focus inside the modal with its respective focusable elements, I'm working with "WEB COMPONENTS, DOW AND SHADOW DOW"
when trying to perform this code snippet, focus still continues to show error and go to elements outside the modal
private setFocus(): void {
const focusableElements = this.querySelectorAll('a[href], button, details, input, select, textarea, [tabindex]:not([tabindex="-1"]), ani-button, ani-textfield');
const firstFocusableElement = focusableElements[0];
const lastFocusableElement = focusableElements[focusableElements.length - 1];
this.addEventListener('keydown', event => {
const isTabbed = event.key === 'Tab' || event.code === '9';
if (!isTabbed) {
return;
}
if (event.shiftKey) {
if (document.activeElement === firstFocusableElement) {
(lastFocusableElement as HTMLElement).focus();
event.preventDefault();
}
} else {
if (document.activeElement === lastFocusableElement) {
(firstFocusableElement as HTMLElement).focus();
event.preventDefault();
}
}
});
(firstFocusableElement as HTMLElement).focus();
}
open(): void {
// this.hidden = false;
this.setAttribute('visible', 'true');
this.setFocus();
}
Related
I have this big class Search, which controls my search bar on my website. Now, when a input is focused, i dont want my s key (which pops out the search bar) to execute when a input is focused. I tried with document.activeElement, but then, the search bar wont even open, whilst the input not being focused. You can see it, under keydown event listener, under Events comment
class Search {
// Describe and create object
constructor() {
this.openButton = document.querySelectorAll('.js-search-trigger');
this.closeButton = document.querySelector('#close-button');
this.searchOverlay = document.querySelector('.search-overlay');
this.searchField = document.getElementById('search-term');
this.typingTimer;
this.events();
this.isSpinnerVisible = false;
this.resultsDiv = document.getElementById('search-overlay__results');
this.previousValue;
console.log(this.openButton);
}
// Events
events() {
this.openButton.forEach(e => {
e.addEventListener('click', () => {
this.openOverlay();
document.body.classList.add('body-no-scroll');
});
})
this.closeButton.addEventListener('click', () => {
this.closeOverlay();
document.body.classList.remove('body-no-scroll');
})
document.addEventListener('keydown', (e) => {
if(e.key === 's' && !(this === document.activeElement)){
this.openOverlay();
document.body.classList.add('body-no-scroll');
console.log("s pressed")
}
if(e.key === 'Escape' && this.isOverlayOpen){
this.closeOverlay();
document.body.classList.remove('body-no-scroll');
console.log("esc pressed");
}
});
this.searchField.addEventListener('keyup', () => {
this.typingLogic();
})
}
// Methods
openOverlay(){
this.searchOverlay.classList.add('search-overlay--active');
this.isOverlayOpen = true;
}
closeOverlay(){
this.searchOverlay.classList.remove('search-overlay--active');
}
typingLogic(){
if(this.searchField.value != this.previousValue){
clearTimeout(this.typingTimer);
if(this.searchField.value){
if(!this.isSpinnerVisible){
this.resultsDiv.innerHTML = '<div class="spinner-loader"></div>';
this.isSpinnerVisible = true;
}
this.typingTimer = setTimeout(this.getResults(),2000);
}else{
this.resultsDiv.innerHTML = '';
this.isSpinnerVisible = false;
}
}
this.previousValue = this.searchField.value;
}
getResults(){
this.typingTimer = setTimeout(()=> {
this.resultsDiv.innerHTML = 'Some here';
this.isSpinnerVisible =false;
},2000)
}
}
export default Search
You can check tagName property of activeElement. And if it is not input then proceed with your code. Update your condition like below.
if(e.key === 's' && document.activeElement.tagName.toLowerCase() != 'input')
I'm trying to hide the "modal" box when the user press Esc key.
So, I first check where the box contains class - 'hidden', which
technically hide the box in UI.
Then if it's not hidden (the box does not contain class - 'hidden') and
appearing on screen, the function will wait for the Esc key for the
box to be disappeared.
Showing and hiding the box parts working just fine, but document.addEventListener part is not working.
const btnopenModal = document.querySelectorAll('.show-modal');
const btnCloseModal = document.querySelector('.close');
const overlay = document.querySelector('.overlay');
const modal =document.querySelector('.modal');
const showModal = function() {
modal.classList.remove('hidden');
overlay.classList.remove('hidden');
};
const hideModal = function() {
modal.classList.add('hidden');
overlay.classList.add('hidden');
}
for(let i = 0; i < btnopenModal.length; i++)
btnopenModal[i].addEventListener('click', showModal);
btnCloseModal.addEventListener('click', hideModal);
overlay.addEventListener('click', hideModal);
if(!overlay.classList.contains('hidden')) {
document.addEventListener('keypress', function(e) {
console.log(e.key);
if(e.key === 'Escape') {
hideModal();
}
})
};
Any other way around for this to work?
I would think that your if statement is evaluated when the webpage first runs, and my guess is that the if statement evaluates to false as it probably does contain the class "hidden" at first. I don't understand why you put it the key handler inside of an if statement, if it is for safety you should put it inside your function like so:
document.addEventListener('keypress', function(e) {
if(!overlay.classList.contains('hidden')) {
console.log(e.key);
if(e.key === 'Escape') {
hideModal();
}
};
})
Move if condition into callback. You want to always add keypress listener, just do not execute hideModal() if !overlay.classList.contains('hidden')
const btnopenModal = document.querySelectorAll('.show-modal');
const btnCloseModal = document.querySelector('.close');
const overlay = document.querySelector('.overlay');
const modal =document.querySelector('.modal');
const showModal = function() {
modal.classList.remove('hidden');
overlay.classList.remove('hidden');
};
const hideModal = function() {
modal.classList.add('hidden');
overlay.classList.add('hidden');
}
for(let i = 0; i < btnopenModal.length; i++)
btnopenModal[i].addEventListener('click', showModal);
btnCloseModal.addEventListener('click', hideModal);
overlay.addEventListener('click', hideModal);
document.addEventListener('keypress', function(e) {
console.log(e.key);
if(e.key === 'Escape' && !overlay.classList.contains('hidden')) {
hideModal();
}
});
I'm converting a dropdown from JQuery to vanilla JS, and I'm having some issues when I click on the dropdown it opens and I can select a value inside of it, but when I click on said value the value will be selected and it will instantly close.
I managed to narrow the problem down to this line
if($('*[data-toggle], *[data-totoggle]').is(e.target) || $('*[data-toggle], *[data-totoggle]').has(e.target).length){
return false;
}
In my vanilla js I replaced the above jquery code with this
if (document.querySelector('*[data-toggle], *[data-totoggle]') === e.target) {
return false;
}
This does not seem to achive the same thing as the jquery has and is functions, are there any equivalent of those in vanilla JS ?
codesandbox example > https://codesandbox.io/s/little-frost-tzefn?file=/src/index.js
Vanilla js version :
(function () {
document.querySelectorAll('*[data-toggle]').forEach(element => element.addEventListener('click', function (e) {
e.preventDefault();
const toToggle = element.dataset.toggle
// Close all other toggle elements and toggle the one you clicked
document.querySelectorAll('*[data-totoggle], *[data-toggle]').forEach(function (toggleElements) {
if (toggleElements.dataset.toggle === toToggle || toggleElements.dataset.totoggle === toToggle) {
toggleElements.classList.toggle('active')
} else if (!toggleElements.classList.contains('onlyClick')) {
toggleElements.classList.remove('active');
}
})
// toggle text if needed
if (element.dataset.toggletext) {
const toggleText = element.dataset.toggletext.split(',')
if (element.classList.contains('active')) {
element.html(toggleText[0])
} else {
element.html(toggleText[1])
}
}
// Remove toggle function from permanent elements
if (element.classList.contains('permanent')) {
element.querySelector('*[data-toggle="' + toToggle + '"]').removeAttribute('data-toggle');
element.querySelector('*[data-totoggle="' + toToggle + '"]').removeAttribute('data-totoggle');
}
}))
// close elements when clicking outside of them
document.addEventListener('mouseup', function (e) {
if (document.querySelector('*[data-toggle], *[data-totoggle]') === e.target) {
return false;
}
document.querySelectorAll('*[data-toggle], *[data-totoggle]').forEach(function (element) {
if (!element.classList.contains('onlyClick')) {
element.classList.remove('active')
}
})
if (document.querySelector('*[data-slidetoggle], *[data-toslidetoggle]') === e.target) {
return false;
}
document.querySelectorAll('*[data-slidetoggle]').forEach(function (element) {
if (!element.classList.contains('onlyClick')) {
element.classList.remove('active')
$('*[data-toslidetoggle]').slideUp();
}
})
});
// slide toggle elements
document.querySelectorAll('*[data-slidetoggle]').forEach(element => element.addEventListener('click', function () {
const slideToggle = this.dataset.slidetoggle
this.classList.toggle('active');
$('*[data-toslidetoggle="' + slideToggle + '"]').slideToggle(200);
if (this.dataset.toggletext) {
const toggleText = this.dataset.toggletext.split(',')
if (this.classList.contains('active')) {
this.html(toggleText[0])
} else {
this.html(toggleText[1])
}
}
}))
document.querySelector('*[data-trigger]').addEventListener('click', function (e) {
const toTrigger = e.target.dataset.trigger
document.querySelector('.' + toTrigger).trigger('click');
})
})();
This is what I tried:
function move(e)
{
if (e.keyCode==32)
{
up=0;
bottonup=650;
var temp="rect("+up+"px,auto,"+bottomup+"px,auto)";
rect2.style.clip=temp;
}
}
function move2(d){
if (d.keyCode==32)
{
up=0;
bottonup=0;
var temp="rect("+up+"px,auto,"+bottomup+"px,auto)";
rect2.style.clip=temp;
}
}
document.onkeydown=move;
document.onkeyup=move2;
My problem is when I press a button or release a button, the transition starts again and because of that, the animation slips.
When working with animation you usually need some kind of condition logic. For ex: waiting for the animation to finish before triggering it again.
let pressed = false
function down () {
// isAnimationDone -> holding key will not re-trigger animation if it's not finish
// pressed -> wait for the key to be release before being able to call the animation again
if (!pressed && isAnimationDone) {
// do animation
pressed = true
}
}
function up () {
pressed = false
}
Every Events has a type. Check against it.
const EventType = {
keyup: "keyup",
keydown: "keydown"
}
const move = (event) => {
if (event.keyCode === 13) {
if (event.type === EventType.keydown) {
console.log(`${event.code} is pressed.`)
} else if (event.type === EventType.keyup) {
console.log(`${event.code} is released.`)
}
}
}
document.body.onkeydown = move
document.body.onkeyup = move
Press Enter to test the code.
I have a enrollment form with some customer related information. If user form is half filled and the user is going to close the tab, then I'll trigger the popup with option of save and exit, exit.
I have some jQuery solution. But nowadays it's not working in all browsers.
Jquery sample Code:
'use strict';
$(document).ready(function() {
$.fn.addEvent = function (obj, evType, fn) {
if (obj.addEventListener) {
obj.addEventListener(evType, fn, false);
return true;
} else if (obj.attachEvent) {
var r = obj.attachEvent('on'+evType, fn);
return r;
} else {
return false;
}
};
$.fn.KeepOnPage = function (e) {
var doWarn = 1;
if (!e) {
e = window.event;
}
if (!e) {
return;
}
if (doWarn == 1) { // and condition whatever you want to add here
e.cancelBubble = true;
e.returnValue = 'Warning!\n\nNavigating away from this page will delete your text if you haven\'t already saved it.';
}
if (e.stopPropagation) {
e.stopPropagation();
}
};
$.fn.addEvent(window, 'beforeunload', $.fn.KeepOnPage);
});
But we need solution in ReactJS. Is there any React library for the browser unload?
Thanks,
Thangadurai
You can add and remove an event listener for the 'beforeunload' event within your componentDidMount and componentWillUnmount lifecycle functions.
https://facebook.github.io/react/docs/component-specs.html
https://developer.mozilla.org/en-US/docs/Web/Events/beforeunload
Example:
...
componentDidMount() {
window.addEventListener('beforeunload', this.keepOnPage);
}
componentWillUnmount() {
window.removeEventListener('beforeunload', this.keepOnPage);
}
keepOnPage(e) {
var message = 'Warning!\n\nNavigating away from this page will delete your text if you haven\'t already saved it.';
e.returnValue = message;
return message;
}
....