Rearrange the layout by dragging and dropping images to switch their places

I've been working on implementing a photo uploader that requires the order of photos to be maintained. In order to achieve this, I have attempted to incorporate a drag and drop feature to swap their positions. However, I am encountering an issue where I am unable to drop images directly on top of each other. Instead, I am required to place them within the surrounding div element. Here is the snippet from component.html:

<div class="container">
  <div class="row">
    <div class="col-12">
      <input type="file" multiple (change)="onSelectFile($event)" />
    </div>
    <div class="col-12">
      <div
        class="photos-container"
        (dragover)="onDragOver($event)"
        (drop)="onDrop($event)"
      >
        <div
          *ngFor="let image of images; index as i"
          class="photo"
          [draggable]="true"
          (dragstart)="onDragStart(i, $event)"
          style="background-color: black;"
        >
          <img [src]="image" style="width: 200px; height: 200px;" />
        </div>
      </div>
    </div>
  </div>
</div>

The code for component.ts is:

onSelectFile(event: any) {
    if (event.target.files.length > 0) {
      this.files = event;
      const files = Array.from(event.target.files);
      files.forEach((file: any) => {
        const reader = new FileReader();
        reader.onload = (e: any) => {
          this.images.push(e.target.result);
        };
        reader.readAsDataURL(file);
        this.imageChangedEvnt = event;
      });
    }
  }

  onDragStart(index: any, event: any) {
    event.dataTransfer.setData("index", index);
  }

  onDragOver(event: any) {
    event.preventDefault();
  }

  onDrop(event: any) {
    const index = event.dataTransfer.getData("index");
    const newIndex = Array.from(event.currentTarget.children).indexOf(
      event.target
    );
    if (newIndex >= 0) {
      const photo = this.images.splice(index, 1)[0];
      this.images.splice(newIndex, 0, photo);
    }
  }

Check out the live demo here: Demo

Despite trying the above code, I'm still facing issues with dropping images directly on top of each other. The swapping functionality only works when the images are placed within the surrounding div.

Answer №1

When looking at the code in onDrop

const newIndex = Array.from(event.currentTarget.children).indexOf(event.target);

If you drop an image on top of another, the event.target will represent <img...../>.

In this scenario, searching for indexOf and <img> within an array <div> results in newIndex being equal to -1.

To handle this, there are two approaches:

1. Avoid placing anything on the drop area and let <img> handle its own translation. Update app.component.html as follows:

<div class="container">
  <div class="row">
    <div class="col-12">
      <input type="file" multiple (change)="onSelectFile($event)" />
    </div>
    <div class="col-12">
      <div
        class="photos-container"
        (dragover)="onDragOver($event)"
        (drop)="onDrop($event)"
        style="
          display: flex;
          flex-direction: column;
          align-items: center;
          background-color: black;">
        <img
          [src]="image"
          *ngFor="let image of images; index as i"
          class="photo"
          [draggable]="true"
          (dragstart)="onDragStart(i, $event)"
          style="width: 200px; height: 200px;"/>
      </div>
    </div>
  </div>
</div>

2. Implement a more intricate solution. Revise onDrop function like so:

onDrop(event: any) {
    const index = event.dataTransfer.getData("index");
    let targetElement;
    if (event.target.tagName === "IMG") {
        targetElement = event.target.parentElement;
    } else if (event.target.tagName === "DIV") {
        targetElement = event.target;
    }
    const newIndex = Array.from(event.currentTarget.children).indexOf(
        targetElement
    );
    if (newIndex >= 0) {
        const photo = this.images.splice(index, 1)[0];
        this.images.splice(newIndex, 0, photo);
    }
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Modifying a css class via javascript

Is it possible to set an element's height using CSS to match the window inner height without directly modifying its style with JavaScript? Can this be achieved by changing a CSS class with JavaScript? One attempted solution involved: document.getEle ...

show additional worth on the console

Just starting out with JavaScript. Trying to display additional values in the console. Uncertain about how to access add-ons. Can anyone help me troubleshoot? Here is my code snippet below: https://jsfiddle.net/6f8upe80/ private sports: any = { ...

Designing a structure with a stationary header, immobile sidebar navigation, and unchanging content using flexbox styling

In the development of a web application, I am utilizing FlexBox for layout design. It is important to note that I am opting for pure flexbox CSS rather than incorporating Bootstrap. Desired Layout Structure: Row1: Consists of a fixed header 64px in heigh ...

Tips for incorporating JSON in server-side rendering using Angular Universal

Currently, I am in the process of developing an angular2-universal app for a university project which is also my bachelor thesis. My goal is to have this app rendered on the server using angular universal. However, I am facing a challenge in loading my .js ...

Executing jQuery AJAX requests in a chain with interdependent tasks

I am struggling to grasp the concept of magic deferred objects with jQuery. Consider the following code snippet: function callWebService(uri, filter, callback) { var data = {}; if (filter && filter != '') data['$filter&apos ...

Error with Angular InjectionToken utilization

We are encountering an issue while trying to inject a value using InjectionToken. The error message that we are receiving is as follows: ERROR in Error encountered resolving symbol values statically. Only initialized variables and constants ...

Conceal the <p> element when the user interacts with the internal href

After creating this document using JQuery, whenever the user clicks on different internal links, a div with id = "change" is loaded which effectively "erases" the content. My challenge at the moment is that while images are successfully deleted, text rema ...

Oops! It seems like there was an issue with trying to access a property that doesn't exist

Whenever I try to insert a new line into my table, I encounter the following error message: ERROR TypeError: Cannot read property 'Nom' of undefined at Object.eval [as updateDirectives] (MedecinsComponent.html:43) at Object.debugUpdateDirect ...

Body section CSS selector

Can a CSS selector be included within the body section of an HTML document? Here's an example of my code (although it is not functioning as expected): <html> <head> </head> <body> <div style= "a[target=_blank] {backgroun ...

How to capture a screenshot of the current screen using Nativescript programmatically

After taking a screenshot in a NativeScript app, is there a way to display a popup asking if the user wants to save the picture? I attempted using the 'nativescript-screenshot' plugin, but it only copies elements within the application: nat ...

When Infinite Scroll is integrated into another file with HTML tags stacked on top, it will not load additional posts when scrolling down

I have implemented an Infinite Scroll feature that dynamically loads more data from a database as users scroll to the bottom of the page. However, I encountered an issue when trying to include this functionality in another .PHP file. If I insert any HTML ...

Request Timeout: The server took too long to respond and the request timed out. Please try again later

I'm encountering an issue when attempting to send a dictionary as a JSON to the express API. The error message I keep receiving is: Error Domain=NSURLErrorDomain Code=-1001 "The request timed out." UserInfo={_NSURLErrorFailingURLSessionTaskErrorKe ...

Steps for integrating a valid SSL certificate into a Reactjs application

After completing my ReactJS app for my website, I am now ready to launch it in production mode. The only hurdle I face is getting it to work under https mode. This app was developed using create-react-app in a local environment and has since been deployed ...

When using jQuery, hover over an li element while ignoring its children

I'm working on customizing a Wordpress menu that has a submenu. I managed to add an arrow to the 'li' element that contains a submenu, and created a hover animation with CSS when the mouse moves over the 'a' tag inside the 'li ...

Using AKS Kubernetes to access a Spring Boot application from an Angular frontend using the service name

I have developed two frontend applications using Angular and a backend application using Spring Boot. Both apps are running in the same namespace. I have already set up two services of type Loadbalancer: The frontend service is named frontend-app-lb (exp ...

Unable to load images on website

I'm having trouble showing images on my website using Node.js Express and an HBS file. The image is not appearing on the webpage and I'm seeing an error message that says "GET http://localhost:3000/tempelates/P2.jpg 404 (Not Found)" Here is the ...

React Hooks: In useEffect(), unable to modify parent component's state

Within my component, I have a form for users to input a title, description, and images. This component is nested within its parent component, and I want the form data to be saved if the user switches sections and returns later without losing their progress ...

Eliminate repetitive elements from an array using a specific merging algorithm

Here's a thought I have: If we have an array of objects like this: [ { "name": "Kirk", "count": 1 }, { "name": "Spock", "count": 1 }, { "name": "Kirk", "count": 1 } ] I would l ...

When utilizing VueJs, it's not possible to retrieve a data property from within a function

I am encountering a challenge when trying to access the data property within the function. Despite my efforts, I seem to be missing something crucial and unable to pinpoint what it is. Here is my class: export default { name: "Contact", component ...

Which function is triggered first - onclick or ng-click?

Currently, I have a button with a validation process occurring on click. The validation process triggers a web service call and other processes if successful. However, I'm uncertain if the validation is actually taking place. This is my page setup: ...