I did drag and drop with several divisions. Everything works correctly but when I do, my inputs are empty...
Do you know why I lose my data (before, after)?
Thanks a lot for your help.
Code :
const divs = document.querySelectorAll(".box")
let dragged
for (let div of divs)
{
div.ondragstart = (e) =>
{
dragged = div
e.dataTransfer.setData("text/plain", div.innerHTML)
};
div.ondragover = (e) => e.preventDefault()
div.ondrop = (e) =>
{
dragged.innerHTML = div.innerHTML
div.innerHTML = e.dataTransfer.getData("text/plain")
};
}
let divTable = document.createElement("div");
divTable.id = "DivTableGroupe" + numTableau;
divTable.className = "box" ;
divTable.draggable = "true";
Your problem is that you are using the div variable in your drop handler.
It is different from the target <div> on which the drop is taking place.
To refer to the target <div> you can use e.currentTarget instead.
Also, there should be a preventDefault() in the drop handler.
div.ondragstart = (e) =>{
dragged = e.currentTarget;
e.dataTransfer.setData("text/plain", div.innerHTML)
};
div.ondrop = (e) => {
e.preventDefault();
dragged.innerHTML = e.currentTarget.innerHTML;
e.currentTarget.innerHTML = e.dataTransfer.getData('text/plain');
};
Related
I'm working on getting the image updated through an event listener as the user leaves the input field. The image changes, but not its href and the input value seems to remain the previous one.
function addBlurListener() {
const inputs = document.querySelectorAll('.form-group.img input.imgLink');
inputs.forEach(input => {
input.addEventListener('blur', function() {
const imageLink = this.value;
const parent = this.parentElement;
let cardImg = parent.querySelector('.card-img');
cardImg.src = imageLink;
cardImg.href = imageLink;
});
});
}
Thanks
I'm trying to make an etch-a-sketch with HTML where I have a div container with lots of div elements in it, using grid display in CSS.
HTML: <div id="canvas"></div>
Then I use JS to add the div elements:
for(let i =1;i<=256;i++){
let squareDiv = document.createElement("div");
canvasElement.appendChild(squareDiv);
canvasElement.setAttribute("draggable","false");}
The draggable attribute doesn't work.
When I click and drag to draw something, it is dragging a faint image as below:
Is there an attribute I could use to disable this ?
Edit: All javascript code:
canvasElement =document.getElementById("canvas")
let isToggling = false;
function enableToggle(e) {
isToggling = true;
}
function disableToggle() {
isToggling = false;
}
function toggle(e) {
if (isToggling === false) {
return;
}
console.log('toggle:', e.target);
e.target.classList.add('red');
}
for(let i =1;i<=256;i++){
let squareDiv = document.createElement("div");
canvasElement.appendChild(squareDiv);
canvasElement.setAttribute("draggable","false");
squareDiv.onmousedown=enableToggle;
squareDiv.onmouseenter=toggle;
squareDiv.onmouseup=disableToggle;
}
You can use e.preventDefault() to prevent the default effect from happening inside your onmousedown event.
Add e.preventDefault() inside your enableToggle(e) function
function enableToggle(e) {
isToggling = true;
e.preventDefault()
}
If that doesn't work add it to toggle() and disableToggle()
I had your exact issue with Etch-A-Sketch and this is how I did it: similar to the other user's answer, this also uses preventDefault() but this activates using the ondragstart HTML attribute.
First, use this JS function to enable preventDefault().
function dragstart (event) {
event.preventDefault()
}
Next, apply dragstart (event) to all your elements in your etch grid. In my case, I used the spread syntax [...nodeList] with the forEach method in a function which runs immediately after generating my grid squares.
let grid = document.getElementById('grid');
function addSquare () {
let sliderValue = document.getElementById('slider').value;
for (let i = 0; i < sliderValue ** 2; i++) {
const square = document.createElement('div');
square.className = 'square';
grid.appendChild(square);
}
}
function modifyGridProperty () {
let square = [...document.getElementsByClassName('square')];
square.forEach(element => {
element.setAttribute('ondragstart', 'dragstart(event)');
});
}
I have a list of items that have two event listeners each, one for clicking on them and making them greyed out and one for the X button that deletes the item.
I have implemented drag and drop functionality using HTML5 api. After two items have switched positions the delete item event listener is removed while the grey event listener still works.
The delete item event listener
li.querySelector(".delete-todo-item").addEventListener("click", deletetodoEventListener)
function deletetodoEventListener(e) {
e.stopPropagation();
const toDo = this.parentElement;
const itemID = toDo.getAttribute("data-id")
todos = todos.filter(function (item) {
return item.timeCreated != itemID;
})
addToLocalStorage(todos);
toDo.remove()
emptyTodoList()
}
The "grey item out" event listener
function toDoEventListener(e) {
console.log("click listner ")
const itemID = this.getAttribute("data-id")
const itemImg = this.querySelector(".todo-image");
if (this.classList.contains("completed")) {
this.classList.remove("completed");
itemImg.src = "media/circle.svg";
todos.forEach(function (item) {
if (item.timeCreated == itemID) {
item.completed = false;
}
});
} else {
this.classList.add("completed");
itemImg.src = "media/check.svg";
todos.forEach(function (item) {
if (item.timeCreated == itemID) {
item.completed = "completed";
}
});
}
addToLocalStorage(todos);
}
The drag and drop functions
function handleDragStart(e) {
this.style.opacity = '0.2';
dragSrcEl = this;
e.dataTransfer.effectAllowed = 'move';
e.dataTransfer.setData('text/html', this.innerHTML);
console.log(e.dataTransfer)
}
function handleDrop(e) {
e.stopPropagation();
e.preventDefault();
const tempId = dragSrcEl.getAttribute("data-id");
const tempClassList = dragSrcEl.classList.value
dragSrcEl.className = this.classList.value;
dragSrcEl.setAttribute("data-id", this.getAttribute("data-id"))
this.className = tempClassList;
this.setAttribute("data-id", tempId)
if (dragSrcEl !== this) {
dragSrcEl.innerHTML = this.innerHTML;
this.innerHTML = e.dataTransfer.getData('text/html');
}
return false;
}
A todo item
<li class="todo-item" data-id="1634245326430" draggable="true">
<div class="todo-item-container">
<div class="img-container">
<img class="todo-image" src="media/circle.svg" alt="">
</div>
<span class="todo-item-content">test</span>
</div>
<span class="delete-todo-item">×</span>
</li>
Full code here: https://github.com/xhuljanoduli/todo-app
This is my first time posting, i always find a solution on my own but this time it is driving me crazy after countless hours of troubleshooting.
Any help will be much appreciated.
I have created a checkbox directly in javascript, and binded a click event the following way :
let checkBox = document.createElement('input');
checkBox.onclick = (e) => {
console.log("click", e);
};
Now I would like to convert this element to plain html, while keeping the associated event. I now I can call checkBox.outerHTML to get the associated html, but the event would disappear.
Is there a way to do the same thing without removing the attached event ?
I don't know why would you need such an approach when you simply can append that element where ever you want. Yet, it is still simple to just fix it the way it is.
Instead of assigning an event, you should assign an attribute like this:
const checkBox = document.createElement('input');
checkBox.setAttribute("onclick", "cbxClicked(event)");
function cbxClicked(e) {
console.log("click", e);
};
console.log(checkBox.outerHTML); // <input onclick="cbxClicked(event)">
Tested well on chrome.
The recommended way is this
window.addEventListner("load",function() {
document.getElementById("checkboxContainer")
.addEventListener("click",function(e) {
const tgt = e.target;
if (tgt.type && tgt.type==="checkbox") {
console.log("click",tgt)
}
});
});
Now you can create your checkboxes before or after load
window.addEventListener("load", function() {
const container = document.getElementById("checkboxContainer");
container.addEventListener("click", function(e) {
const tgt = e.target;
if (tgt.type && tgt.type === "checkbox") {
console.log("click", tgt)
}
});
const inp = document.createElement("input")
inp.type = "checkbox";
inp.value = "dynamic";
container.appendChild(inp);
});
<div id="checkboxContainer">
<input type="checkbox" value="static" />
</div>
I'm trying to move individual li elements from one ul to another when a checkbox is selected.
Full code can be found here:http://jsfiddle.net/8f27L0q3/1/
My function that moves the li item can be found below.
ul.addEventListener('change', (e) => {
const checkbox = e.target;
const checked = checkbox.checked;
const listItem = e.target.parentNode.parentNode;
const completedItems =
document.querySelector('.completedItems');
const label = document.querySelector('.completedLabel');
if (checked) {
completedItems.appendChild(listItem);
label.style.display = 'none';
}
});
Once the li is moved to the other ul, the child span containing a label and checkbox disappear. This functionality works when the first child li moves but doesn't work when a li after the first child is moved. Also the first li's span disappears and therefore cannot be moved to the other ul
Looks like you are asking for the .completedLabel selector globally when you just need to search for it inside the item that was clicked.
May reducing the scope of the query selector to the element you are storing in listItem may work. Here is an example:
const label = listItem.querySelector('.completedLabel');
That way it works reusing your sample code:
//move li item to completed list when checkbox selected
ul.addEventListener('change', (e) => {
const checkbox = e.target;
const checked = checkbox.checked;
const listItem = e.target.parentNode.parentNode;
const completedItems = document.querySelector('.completedItems');
const label = listItem.querySelector('.completedLabel');
if (checked) {
completedItems.appendChild(listItem);
label.style.display = 'none';
}
});
However the implementation can be tweaked a little bit more.
would you mind reconsidering your strategy in solving this case? It is recommended to work with data such as arrays and objects instead of DOM nodes.
Please consider this example
const form = document.forms.form;
const todoList = document.querySelector('#todoList');
const completedList = document.querySelector('#completedList');
const tasks = [];
form.addEventListener('submit', handleSubmit, true);
todoList.addEventListener('change', handleInputChange, true);
function handleSubmit(event) {
event.preventDefault();
const task = this.task;
if (task.value === '') {
return;
}
const item = createTask(task.value);
tasks.push(item);
task.value = '';
syncTodoList();
}
function handleInputChange(event) {
const target = event.target;
if (target.nodeName === 'INPUT') {
const id = event.target.id;
const task = tasks.find(task => task.id === parseInt(id, 10));
task.status = 'completed';
syncTodoList();
syncCompletedList();
}
}
function createTask(task) {
return {
id: Date.now(),
text: task,
status: 'todo'
};
}
function syncTodoList() {
const todos = tasks
.filter(task => task.status === 'todo')
.map(task => `<li>${task.text} <input type="checkbox" id="${task.id}"></li>`)
.join('');
todoList.innerHTML = todos;
}
function syncCompletedList() {
const completeds = tasks
.filter(task => task.status === 'completed')
.map(task => `<li>${task.text}</li>`)
.join('');
completedList.innerHTML = completeds;
}
<form name="form">
<input id="task">
<button>Send</button>
</form>
<p>Todo</p>
<ul id="todoList"></ul>
<p>Completed</p>
<ul id="completedList"></ul>