Search code examples
angulartypescriptdrag-and-dropcss-grid

Is it possible to get the gridColumnStart of empty cells in CSS Grid?


So I need to be able to drag the images and drop them into an empty grid cell, however I can't seem to get the cell position at all. I understand I could use a table for this but the data is dynamic so it needs to be filled by column from left to right hence using display grid for it.

I'm essentially trying to recreate how a PC desktop acts when dragging and dropping items such as folders or images. Current layout

I'm able to set an image position manually using gridColumnStart and gridColumnEnd but I need to be able to drag and get the empty cells position on drop event. Layout of the grid showing empty cells

I have the drag events set on each of the images. The dragging code

If I understand it correctly the empty cells cant be targeted as they aren't technically part of the DOM so would there be a better way to do this?

.app-container {
    display: grid;
    grid-template-columns: repeat(17, 1fr);
    grid-template-rows: repeat(8, 1fr);
    gap: 0px 0px;
    grid-auto-flow: column;
    // grid-template-areas: 
    // ". . . . . . . . . . . . . . . . ." 
    // ". . . . . . . . . . . . . . . . ." 
    // ". . . . . . . . . . . . . . . . ." 
    // ". . . . . . . . . . . . . . . . ." 
    // ". . . . . . . . . . . . . . . . ." 
    // ". . . . . . . . . . . . . . . . .";
}
<div class="app-container">
            
</div>

Thanks.


Solution

  • Please do not link pictures. Instead write the code, so we can copy and working with it. You can use a library like Materials cdkDrag or my library ngx-explorer-dnd which is explicitly made for dragging operations inside a grid. It's inspired from cdkDrag. But at this time it is an alpha. Here is a link to a Stackblitz example.

    Here is the link to ngx-explorer-dnd. To use it is very straight forwarded

    HTML

    <div
      class="outer-container"
      ngxExplorerDndContainer
      ngxDragSelection
      (dragInProgress)="dragInProgress($event)"
      (selectedElementsChange)="selectedElementsChange($event)"
      (targetChange)="targetChange($event)"
      (drop)="drop($event)"
      [selectionAllowed]="!isDragInProgress"
      [badge]="badgeCount"
      [cancelAnimation]="cancelAnimation"
      [selectionDivElement]="myElement"
    >
      <app-file
        ngxExplorerDndElement
        [dndElementData]="item"
        [myId]="item"
        *ngFor="let item of files"
      >
      </app-file>
    
      <app-folder
        ngxExplorerDndTarget
        ngxExplorerDndElement
        [dndElementData]="item"
        [myId]="item"
        *ngFor="let item of directories"
      >
      </app-folder>
    </div>
    

    Code

    ...
    dragInProgress(event: boolean) {
        this.isDragInProgress = event;
      }
    
      selectedElementsChange(event: { count: number; data: FileFolder[] }) {
        for (let _data of this.fileFolderComponents) {
          _data.selected = false;
        }
    
        for (let _data of event.data) {
          _data.selected = true;
        }
      }
    
      drop(event: any) {
        // Show the optional event data and the selected components
        // Do whatever you wanna do with it! :-)
        console.log(
          event,
          this.fileFolderComponents.filter((f) => f.selected)
        );
    
        if (this.cancelAnimation) {
          // false? No target under mouse
          for (let _fileFolder of this.fileFolderComponents.filter(
            (f) => f.selected
          )) {
            if (_fileFolder.id && _fileFolder.id.includes('File')) {
              this.files.splice(
                this.files.findIndex((f) => f === _fileFolder.id),
                1
              );
            }
            if (_fileFolder.id && _fileFolder.id.includes('Folder')) {
              this.directories.splice(
                this.directories.findIndex((f) => f === _fileFolder.id),
                1
              );
            }
          }
        }
      }
    ...
    

    The lib has a sorting function I say. The result can be looks like this: enter image description here