javascripthtmlsassdrag-and-dropdata-transfer

I return nothing ondrop how to fix it?


When iam dropping my div with an image inside i get nothing and after i am trying to get it ID i get null of course. But how can i get info from a div with image and append row with it? Code here or check codepen: https://codepen.io/13reathcode/pen/NWBmZpb

'use strict';

let queuedImagesArray = [],
    queuedForm = document.querySelector('#queued-form'),
    queuedDiv = document.querySelector('.queued-div'),
    inputDiv = document.querySelector('.input-div'),
    input = document.querySelector('.input-div input');

const colors = ['#FF7F7F', '#FFBF7F', '#FFDF7F', '#BFFF7F', '#7FFF7F', '#7FBFFF', '#7F7FFF'],
    rows = document.querySelectorAll('.content__row'),
    cards = document.querySelectorAll('.content__card'),
    addCard = document.getElementById('addCard');

// Queued Images

const onDragStart = (event) => {
    console.log('Dragging');
    event.dataTransfer.setData('id', event.target.id);

    setTimeout(() => {
        event.target.style.visibility = 'hidden';
    }, 100);
};

const onDragEnd = (event) => {
    console.log('Ended dragging');
    event.target.style.visibility = 'visible';
};

const displayQueuedImages = () => {
    let images = '';
    queuedImagesArray.forEach((image, index) => {
        images += `
        <div class="image" draggable="true" id="${(Date.now() + '').slice(-10) + index}">
            <img width='100' height='100' style="pointerEvents:none;" id="${index}" ondragstart="onDragStart" ondragend="onDragEnd"
            src="${URL.createObjectURL(image)}" alt="image" />
            <span style="color:black;font-size:2rem" onclick="deleteQueuedImage(${index})">&times;</span>
        </div>
        `;
    });
    queuedDiv.innerHTML = images;
};

const deleteQueuedImage = (index) => {
    queuedImagesArray.splice(index, 1);
    displayQueuedImages();
};

input.addEventListener('change', () => {
    const files = input.files;
    for (let i = 0; i < files.length; i++) {
        queuedImagesArray.push(files[i]);
    }
    queuedForm.reset();
    displayQueuedImages();
});

inputDiv.addEventListener('drop', (e) => {
    e.preventDefault();
    const files = e.dataTransfer.files;
    for (let i = 0; i < files.length; i++) {
        if (!files[i].type.match('image')) return;
        if (queuedImagesArray.every((image) => image.name !== files[i].name))
            queuedImagesArray.push(files[i]);
    }
    displayQueuedImages();
});

const onDrag = (event) => {
    event.preventDefault();
};
// Problem here 
const onDrop = (event) => {
    event.preventDefault();
    const draggedCardId = event.dataTransfer.getData('id'); // nothing
    const draggedCard = document.getElementById(draggedCardId); // null
    event.target.appendChild(draggedCard);
};

rows.forEach((row, index) => {
    const label = row.querySelector('.content__label');
    label.style.backgroundColor = colors[index];
    row.ondragover = onDrag;
    row.ondrop = onDrop;
});

<main>
            <section class="section" id="section--1">
                <div class="section__title">
                    <h2 class="section__description">Tier list app</h2>
                    <h3 class="section__text">Start dragging to move cards</h3>
                </div>
                <div class="content" id="content">
                    <div class="content__row">
                        <div class="content__label">S (The best)</div>
                      
                    </div>
                    <div class="content__row">
                        <div class="content__label">A (Great)</div>
                    </div>
                    <div class="content__row">
                        <div class="content__label">B (Good)</div>
                    </div>
                    <div class="content__row">
                        <div class="content__label">C (Mediocre)</div>
                    </div>
                    <div class="content__row">
                        <div class="content__label">D (Bad)</div>
                    </div>
                    <div class="content__row">
                        <div class="content__label">E (Horrible)</div>
                    </div>
                    <!-- <div class="content__row">
                        <div class="content__label">F (Worst^_^)</div>
                    </div>  -->
                </div>
            </section>

            <form id="queued-form">
                <div class="queued-div"></div>
            </form>

            <div class="input-div">
                <p>Drag & drop images here or <span class="browse">Browse</span></p>
                <input
                    type="file"
                    class="file"
                    multiple="multiple"
                    accept="image/png, image/jpeg, image/jpg"
                />
            </div>
        </main>
* {
    margin: 0;
    padding: 0;
    box-sizing: inherit;
}

html {
    font-size: 62.5%; // 10px = 1rem
    box-sizing: border-box;
}

body {
    font-family: 'Open Sans', sans-serif;
    font-weight: 300;
    color: #555;
    line-height: 1.5;
}

.input-div {
    width: 70%;
    height: 200px;
    border-radius: 5px;
    display: flex;
    justify-content: center;
    align-items: center;
    text-align: center;
    margin: 5rem auto;
    border: 2px dotted black;
    background-color: white;
    position: relative;

    .browse {
        color: black;
        font-weight: bold;
    }
}

.file {
    width: 100%;
    height: 100%;
    position: absolute;
    opacity: 0;
    cursor: pointer;
}

.queued-div {
    width: 70%;
    min-height: 200px;
    display: flex;
    margin: 5rem auto;
    justify-content: flex-start;
    flex-wrap: wrap;
    gap: 0.5rem;
    position: relative;
    border-radius: 5px;
    border: 2px dotted black;
    background-color: white;

    .image {
        height: 10rem;
        border-radius: 5px;
        box-shadow: 0 0 5px rgba(0, 0, 0, 0.15);
        overflow: hidden;
        position: relative;

        &:nth-child(4n) {
            margin-right: 0;
        }

        img {
            height: 100%;
            width: 100%;
        }

        span {
            position: absolute;
            top: -4px;
            right: 4px;
            cursor: pointer;
            font-size: 22px;
            color: white;

            &:hover {
                opacity: 0.8;
            }
        }
    }
}

@mixin center {
    display: flex;
    justify-content: center;
    align-items: center;
}

// SECTIONS

.section {
    padding: 1.8rem 3rem;

    &__title {
        max-width: 80rem;
        margin: 0 auto 2rem auto;
        text-align: center;
        text-transform: uppercase;
    }

    &__description {
        color: lightgreen;
        font-size: 1.8rem;
    }

    &__text {
        font-size: 2.5rem;
    }

    &__button {
        font-size: 2rem;
        text-transform: uppercase;
        text-decoration: none;
        padding: 1rem 2rem;
        display: inline-block;
        border-radius: 3rem;
        position: relative;
        background-color: lightgreen;
        color: #fff;

        border: none;
        cursor: pointer;
    }
}

// CONTENT
.content {
    width: 70vw;
    min-height: 10vh;
    padding: 0rem;
    box-sizing: content-box;
    border: 3px solid #000;

    display: flex;
    flex-wrap: wrap;
    flex-direction: column;
    margin: 0 auto;

    &__row {
        width: 100%;
        box-sizing: content-box;
        flex-wrap: wrap;
        height: 8.5rem;
        background-color: #1a1a17;
        display: flex;

        &:not(:last-child) {
            border-bottom: 2px solid #000;
        }
    }

    &__label {
        font-size: 2rem;
        font-weight: 400;
        height: 100%;
        width: 15rem;
        background-color: #555;
        color: #333;
        border-right: 3px solid #000;

        @include center;
    }

    &__card {
        @include center;

        &:focus,
        &:active {
            cursor: pointer;
        }
    }
}

When i was adding images one by one everything was fine but when i changed button to input zone i can't get anything from new images.


Solution

  • There is a small issue in how you create your img elements: the ondragstart and ondragend event handlers aren't being assigned properly.

    Currently, your img elements look something like:

    <img id="0" ondragstart="onDragStart" ondragend="onDragEnd" src=... />
    

    However, setting ondragstart to equal onDragStart doesn't actually invoke the function when the event is fired. Same with ondragend and onDragEnd. To do so, you have to actually invoke the functions with onDragStart(event) and onDragEnd(event).

    This is because every HTML event handler attribute is implicitly wrapped in:

    (event) => { /** the attribute value */ }
    

    In other words, currently, your handlers are equivalent to:

    (event) => { onDragStart }
    // and
    (event) => { onDragEnd }
    

    instead of

    (event) => { onDragStart(event) }
    // and
    (event) => { onDragEnd(event) }
    

    which is given by

    <img id="0" ondragstart="onDragStart(event)" ondragend="onDragEnd(event)" src=... />
    

    So the fix is simply to fix the img generation code to:

    images += `
    <div class="image" draggable="true" id="${(Date.now() + '').slice(-10) + index}">
        <img width='100' height='100' id="${index}" 
            ondragstart="onDragStart(event)" ondragend="onDragEnd(event)" 
            src="${URL.createObjectURL(image)}" alt="image" />
        <span style="color: black; font-size: 2rem" 
            onclick="deleteQueuedImage(${index})">&times;</span>
    </div>`;