How to set and use the local storage data of the left sidebar width after resizing the sidebar and reloading the page?
I have created a local storage data and retrieve it using the codes below but after reloading the page the resized sidebar is going back to its default width. It should have an "onload" event attribute?
Here is the link where I get the codes https://htmldom.dev/create-resizable-split-views/
Credit to: htmldom.dev for sharing this code
document.addEventListener('DOMContentLoaded', function () {
// Query the element
const resize = document.getElementById('dragMe');
const leftSide = resize.previousElementSibling;
const rightSide = resize.nextElementSibling;
// The current position of mouse
let x = 0;
let y = 0;
let leftWidth = 0;
// Handle the mousedown event
// that's triggered when user drags the resize
const mouseDownHandler = function (e) {
// Get the current mouse position
x = e.clientX;
y = e.clientY;
leftWidth = leftSide.getBoundingClientRect().width;
// Attach the listeners to `document`
document.addEventListener('mousemove', mouseMoveHandler);
document.addEventListener('mouseup', mouseUpHandler);
};
const mouseMoveHandler = function (e) {
// How far the mouse has been moved
const dx = e.clientX - x;
const dy = e.clientY - y;
// Set a new left width and saving to local storage
const newLeftWidth = ((leftWidth + dx) * 100) / resize.parentNode.getBoundingClientRect().width;
leftSide.style.width = `${newLeftWidth}%`;
resize.style.cursor = 'col-resize';
document.body.style.cursor = 'col-resize';
leftSide.style.userSelect = 'none';
leftSide.style.pointerEvents = 'none';
localStorage.setItem('newLeftWidth', leftSide.style.width);
const localNewLeftWidth = localStorage.getItem('newLeftWidth');
leftSide.style.width = localNewLeftWidth;
console.log('log:' + localNewLeftWidth);
rightSide.style.userSelect = 'none';
rightSide.style.pointerEvents = 'none';
};
const mouseUpHandler = function () {
resize.style.removeProperty('cursor');
document.body.style.removeProperty('cursor');
leftSide.style.removeProperty('user-select');
leftSide.style.removeProperty('pointer-events');
rightSide.style.removeProperty('user-select');
rightSide.style.removeProperty('pointer-events');
// Remove the handlers of `mousemove` and `mouseup`
document.removeEventListener('mousemove', mouseMoveHandler);
document.removeEventListener('mouseup', mouseUpHandler);
};
// Attach the handler
resize.addEventListener('mousedown', mouseDownHandler);
});
If you want to load the stored position when the page is loaded, you might want to use the DOMContentLoaded event:
document.addEventListener("DOMContentLoaded", () => {
const localNewLeftWidth = localStorage.getItem('newLeftWidth');
leftSide.style.width = `${localNewLeftWidth}%`;
console.log('log: ' +`${localNewLeftWidth}%`);
// Possibly load other stuff here
});
Note that you have to add this event listener outside of your mouseMoveHandler.
You can learn more about the DOMContentLoaded event here: https://developer.mozilla.org/de/docs/Web/API/Window/DOMContentLoaded_event.
Related
I've just followed this tutorial on Youtube to add a drag scroll to any scroll elements (https://www.youtube.com/watch?v=C9EWifQ5xqA&t=115s&ab_channel=WesBos) It worked and was extremely helpful. My only issue is I would like to apply this to multiple sliders on one page. I believe I have to create some form of 'For Loop' but I'm struggling to get anything working. Whenever I seem to add a For Loop it breaks the functionality and stops working.
Heres the JS I currently have which works.
var scrollSlider = document.querySelector(".scroll-slider1, .scroll-slider2");
let isDown = false;
let startX;
let scrollLeft;
scrollSlider.addEventListener('mousedown', (e) => {
e.preventDefault();
isDown = true;
scrollSlider.classList.add('active');
startX = e.pageX;
scrollLeft = scrollSlider.scrollLeft;
});
scrollSlider.addEventListener('mouseleave', () => {
isDown = false;
scrollSlider.classList.remove('active');
});
scrollSlider.addEventListener('mouseup', () => {
isDown = false;
scrollSlider.classList.remove('active');
});
scrollSlider.addEventListener('mousemove', (e) => {
e.preventDefault();
if(!isDown) return;
const x = e.pageX;
const scroll = x - startX;
scrollSlider.scrollLeft = scrollLeft - scroll;
});
Could anyone help me add some form of loop to this, so it gets applied to every drag slider on the page rather than just the first slider? Thanks.
// Get all scroll sliders
const scrollSliders = document.querySelectorAll(".scroll-slider1, .scroll-slider2");
// Loop through each scroll slider
scrollSliders.forEach(scrollSlider => {
let isDown = false;
let startX;
let scrollLeft;
// Add event listeners for each scroll slider
scrollSlider.addEventListener('mousedown', (e) => {
e.preventDefault();
isDown = true;
scrollSlider.classList.add('active');
startX = e.pageX;
scrollLeft = scrollSlider.scrollLeft;
});
scrollSlider.addEventListener('mouseleave', () => {
isDown = false;
scrollSlider.classList.remove('active');
});
scrollSlider.addEventListener('mouseup', () => {
isDown = false;
scrollSlider.classList.remove('active');
});
scrollSlider.addEventListener('mousemove', (e) => {
e.preventDefault();
if(!isDown) return;
const x = e.pageX;
const scroll = x - startX;
scrollSlider.scrollLeft = scrollLeft - scroll;
});
});
I'm trying to independently implement the ability to drag a block through a class. However getting a problem when trying to overlay an eventListener...
class Form {
constructor() {
//pass
}
DOMGenerator(elemClass) {
const element = document.createElement('div');
element.classList.add(elemClass);
return element;
}
Draw() {
const form = this.DOMGenerator('window'),
label = this.DOMGenerator('window_label'),
controls = this.DOMGenerator('window_controls'),
close = this.DOMGenerator('close'),
minimize = this.DOMGenerator('minimize'),
maximize = this.DOMGenerator('maximize')
label.addEventListener('mousedown', event => {
const offsetX = event.offsetX;
const offsetY = event.offsetY;
document.addEventListener('mousemove', listener = event => {
let pageX = event.pageX;
let pageY = event.pageY;
form.style.left = `${pageX - offsetX}px`;
form.style.top = `${pageY - offsetY}px`;
})
document.addEventListener('mouseup', () => {
document.removeEventListener('mousemove', listener, false);
})
})
controls.append(close, minimize, maximize);
label.append(controls);
form.append(label);
document.body.append(form);
}
}
new Form().Draw();
When executing the code and click on label element I get
Uncaught ReferenceError: listener is not defined
at HTMLDocument.<anonymous> (main.js:31:63)
(anonymous) # main.js:31
However, if I execute code OUTSIDE the class on an existing DOM element, then everything works as it should... So then I tried to change function declaration like this
document.addEventListener('mousemove', function listener(event) {
let pageX = event.pageX;
let pageY = event.pageY;
form.style.left = `${pageX - offsetX}px`;
form.style.top = `${pageY - offsetY}px`;
})
It grabs the window and sticks it to the cursor, but fails to execute removeEventListener with the same error
Uncaught ReferenceError: listener is not defined
at HTMLDocument.<anonymous> (main.js:31:63)
You haven't defined a function named listener anywhere.
You can define a listener function outside.
const listener = (event) => {
// some code
}
element.addEventListener('mousemove', listener);
element.removeEventListener('mousemove', listener);
Here you are just defining a named function expression. You cannot access from outside with the name of the listener.
document.addEventListener('mousemove', function listener(event) {
let pageX = event.pageX;
let pageY = event.pageY;
form.style.left = `${pageX - offsetX}px`;
form.style.top = `${pageY - offsetY}px`;
})
Let's try to access it. The result we will see is undefined.
document.addEventListener('mousemove', function listener(event) {
...
})
console.log(typeof listener); -> undefined
You can do something like below for the solution.
Draw() {
const form = ...
let pageX;
let pageY;
let offsetX;
let offsetY;
const listener = (event) => {
pageX = event.pageX;
pageY = event.pageY;
form.style.left = `${pageX - offsetX}px`;
form.style.top = `${pageY - offsetY}px`;
}
label.addEventListener('mousedown', event => {
offsetX = event.offsetX;
offsetY = event.offsetY;
document.addEventListener('mousemove', listener)
document.addEventListener('mouseup', () => {
document.removeEventListener('mousemove', listener, false);
})
})
...
}
I'm trying to create drag-and-drop and I want my window to be scrolled in case I start the drag and reach the top / bottom of my page until I come out of the top/bottom "zone". So far what I have written works differently and I can't figure out a way to make it work the way I want.
Is there any way to do so using vanilla JS?
let mouseDown = true;
function mousedown() {
mouseDown = true;
}
function mouseup() {
mouseDown = false;
}
if (!document.querySelector(".arrow-timeline")) {
this.element.addEventListener('mousemove', function() {
let x, y;
function handleMouse(e) {
// Verify that x and y already have some value
if (x && y && mouseDown) {
// Scroll window by difference between current and previous positions
window.scrollBy(e.clientX - x, e.clientY - y);
}
// Store current position
x = e.clientX;
y = e.clientY;
}
// Assign handleMouse to mouse movement events
document.onmousedown = mousedown;
document.onmousemove = handleMouse;
document.onmouseup = mouseup;
})
}
My problem is when I add a mousemove listener on document, all divs are moving but when I add a mousemove listener on my element, I have to move the cursor slowly.
Here is my code :
let componentsItems = document.getElementsByClassName("componentItem");
[].forEach.call(componentsItems, function (componentItem) {
componentItem.addEventListener("click", function (event) {
let selectedComponent = getComponentToDisplay(event.target.getAttribute("data-exchange"));
let mapContainer = document.getElementById("mapContainer");
let mainElement = document.createElement("div");
mainElement.innerHTML = "test";
mainElement.style.position = "absolute";
mapContainer.appendChild(mainElement);
mainElement.addEventListener("mouseup", function (e) {
isDown = false;
});
mainElement.addEventListener("mousedown", function (e) {
isDown = true;
offset = [
mainElement.offsetLeft - e.clientX,
mainElement.offsetTop - e.clientY
];
});
document.addEventListener("mousemove", function (e) {
e.preventDefault();
mousePosition = {
x: e.clientX,
y: e.clientY
};
let left = (mousePosition.x + offset[0]);
let top = (mousePosition.y + offset[1]);
if(isDown){
if(mapContainer.offsetTop < top && mapContainer.offsetWidth > left){
mainElement.style.left = left + 'px';
mainElement.style.top = top + 'px';
}
}
});
});
});
For each component in my menu, I add an onclick listener to appendChild element in the "MapContainer" div.
The drag and drop problem.
The problem is you are attaching multiple mousemove listeners to document, and each one with every one of the different mainElements.
The solution:
Remember which element we are about to move.
mainElement.addEventListener("mousedown", function (e) {
isDown = true;
element = mainElement;
offset = [
mainElement.offsetLeft - e.clientX,
mainElement.offsetTop - e.clientY
];
});
On the outter scope (outside foreach) create a unique mousemove event listener, and update the element that we mousedowned before.
document.addEventListener("mousemove", function (e) {
e.preventDefault();
mousePosition = {
x: e.clientX,
y: e.clientY
};
let left = (mousePosition.x + offset[0]);
let top = (mousePosition.y + offset[1]);
if(isDown){
if(mapContainer.offsetTop < top && mapContainer.offsetWidth > left){
element.style.left = left + 'px';
element.style.top = top + 'px';
}
}
});
Other ways to solve this problem is to create (and delete) the eventlistener on the mousedown and mouseup event handlers respectively. But I believe it's less efficient and definitely more complicated.
I making a simple drag'n'drop interface. I have a bunch of containers ("wrapper") and some dynamically added items ("dragElement") in one of them. So I need, when I move item over another container, JS detect it and move the item there when the drag is finished.
I tried to detect container with "onmouseover" and "mouseup" when dragging item, but had no success, because, actually, mouse always was over the dragged element.
So how can I detect container when drag item? In pure JS please...
document.onmousedown = function(e) {
var dragElement = e.target;
if (!dragElement.classList.contains('draggable')) return;
var coords, shiftX, shiftY, detectPage;
startDrag(e.clientX, e.clientY);
document.onmousemove = function(e) {
moveAt(e.clientX, e.clientY);
};
wrapper.onmouseover = function(e) {
detectPage = e.target;
console.log(detectPage);
};
dragElement.onmouseup = function() {
finishDrag();
};
function startDrag(clientX, clientY) {
shiftX = clientX - dragElement.getBoundingClientRect().left;
shiftY = clientY - dragElement.getBoundingClientRect().top;
dragElement.style.position = 'fixed';
document.body.appendChild(dragElement);
moveAt(clientX, clientY);
};
function finishDrag() {
dragElement.style.top = parseInt(dragElement.style.top) - wrapper.getBoundingClientRect().top + 'px';
dragElement.style.position = 'absolute';
wrapper.onmouseup = function(e) {
var selectPage = e.target;
}
wrapper.appendChild(dragElement);
document.onmousemove = null;
dragElement.onmouseup = null;
};
function moveAt(clientX, clientY) {
var newX = clientX - shiftX;
var newY = clientY - shiftY;
if (newX < 0) newX = 0;
if (newX > wrapper.offsetWidth - dragElement.offsetWidth) {
newX = wrapper.offsetWidth - dragElement.offsetWidth;
}
dragElement.style.left = newX + 'px';
dragElement.style.top = newY + 'px';
};
return false;
};
Well, no one help. So one free day gone to find the solution. All I can found is to delete function finishDrag() from dragElement.onmouseup and change it to the code below.
If in shorter, when onmouseup comes, dragElement must go to display:none and now we can get access to the object near the mouse cursor through elementFromPoint. When we done with it, we can easily detects container, bring an element back to display:block and put it to that container...
Hope, it helps to someone...
dragElement.onmouseup = function(e) {
dragElement.style.display = 'none';
var selectPage = document.elementFromPoint(e.clientX, e.clientY);
dragElement.style.display = 'block';
dragElement.style.top = parseInt(dragElement.style.top) - selectPage.getBoundingClientRect().top + 'px';
dragElement.style.position = 'absolute';
selectPage.appendChild(dragElement);
document.onmousemove = null;
dragElement.onmouseup = null;
};