angular / components

Component infrastructure and Material Design components for Angular
https://material.angular.io
MIT License
24.32k stars 6.73k forks source link

Support copying items from source container #13906

Open TKul6 opened 5 years ago

TKul6 commented 5 years ago

Bug, feature request, or proposal:

Feature request

What is the expected behavior?

When dragging (in order to copy) items from the source container the item should not leave the _initalContainer. In addition, when the item is being copy, the sorting behavior should be disabled (Not sure about that...)

What is the current behavior?

Currently the items can not really be copied to another container, There was basic support developed to solve #13100, but still the UX is not so friendly (the item is disappeared from the source container and then re added), I think it would be best if the item will remained in its old position and not disappear.

What is the use-case or motivation for changing an existing behavior?

The user preform search and then the results appears in a table, I want to be able to copy the items from the search results to designated zones (which might already include items) without loosing the item in the search list

Which versions of Angular, Material, OS, TypeScript, browsers are affected?

Is there anything else we should know?

I started to work about some simple example 4a5b254. (it is in very early stage, but it should explain the basic behavior).

What do you say? Thanks,

shanedev6 commented 5 years ago

I too agree with the proposed behavior. It also feels natural for the drop to be able to be in any position instead of the current position from the previous list similar to what occurs in the transferArrayItem.

Example App: https://stackblitz.com/edit/mat-drag-drop-xfdfuh

kingecg commented 5 years ago

I also need this feature. A common use case is pick some component from a components list to view

Harpush commented 4 years ago

Very much needed for repository like UI where you add components by dragging them but they are never removed from the source list

tchunwei commented 4 years ago

Check this out, manage to get some "copy" behavior working https://stackblitz.com/edit/angular-krmecd

clabough commented 4 years ago

Check this out, manage to get some "copy" behavior working https://stackblitz.com/edit/angular-krmecd

Thanks @tchunwei Hopefully they can get this functionality implemented natively.

jelbourn commented 4 years ago

We started talking about potential APIs for this today; no ETA or anything like that, but we're thinking about it

jeneg commented 4 years ago

Yes, please. Copy behavior without blinking of source item is really needed. @tchunwei thanks for reference

DerekJDev commented 3 years ago

Any update on this?

Eve-Sama commented 3 years ago

Check this out, manage to get some "copy" behavior working https://stackblitz.com/edit/angular-krmecd

Method getItemIndex was deprecated in v10

norsemangrey commented 2 years ago

Anything happening on this issue?

ke-ly commented 2 years ago

Check this out, manage to get some "copy" behavior working https://stackblitz.com/edit/angular-krmecd

Method getItemIndex was deprecated in v10

https://stackblitz.com/edit/angular-ivy-t4qdiq?file=src/app/app.component.html

you don't need getItemIndex and lodash

BenRacicot commented 2 years ago

@jelbourn had an idea for this problem,

It's a very clunky UX to not be able to show the user where their "dragging" element came from.

copy could simply be a boolean option on origin location options.

I'm open to helping in any way I can.

rodcisal commented 2 years ago

any solution to this issue? I'd love to be able to copy elements from one list to another, I have a very long source list that when gets mutated (element removed from it) it causes performance problems

avinash1203 commented 2 years ago

It will be nice to have this.

avrit commented 2 years ago

its just a simple flag, can you add this?

louis-lau commented 2 years ago

any solution to this issue? I'd love to be able to copy elements from one list to another, I have a very long source list that when gets mutated (element removed from it) it causes performance problems

Though I'm all for solving this issue, it doesn't sound like a solution to your performance problem. Are you using trackBy? For very very long lists that are simply too much for the browser I'd check out virtual scrolling.

joelkesler commented 2 years ago

I also have a use for this.

We are building an interactive editor, with the idea that you can drag objects from a list of items into the editor window to add a new instance of that item. Having the ability to copy one cdkDrag into a specific cdkDropList would be lovely

JWess commented 2 years ago

I have a UI where I need to be able to drag-and-drop employees from the "Employees" area to one or more crews in the "Crews" area. However, employees can be drug to multiple crews, so I don't want them to act like they are leaving the Employees list and then suddenly "reappear" when the drop happens.

image

BenRacicot commented 2 years ago

Hey @andrewseguin, is this copying from a source feature no longer being considered for Angular's drag and drop?

JJKid commented 1 year ago

Any updates on this feature??

lappjeff commented 1 year ago

Still waiting for this, would love to get an update from someone!

RandomNameUser commented 1 year ago

Just to add another vote for this. It doesn't seem like a complicated request, but there are quite a few use cases that require it...

ng-sp7 commented 1 year ago

Thread is open since last 4 years. Any update on this feature?

DerekJDev commented 1 year ago

For anybody waiting on this, if you're looking for a solid replacement, check out SortableJS.

Moku151 commented 1 year ago

Any updates on this feature?

louis-lau commented 1 year ago

Any updates on this feature?

Another person asked this a month ago, on this issue that's been open for 5 years. If there were updates, they would be visible here. A bunch of people are subscribed to this issue for actual updates and will get notified when you ask this useless question. Can we all agree to stop asking it? If you have nothing to add to the discussion, just add a +1 to the issue and subscribe to notifications.

Moku151 commented 1 year ago

I empathize with your frustration regarding my previous comment. However, my intention was to highlight the ongoing demand and importance of addressing this issue. The fact that multiple users keep asking about it underscores the widespread need for a solution.

BenRacicot commented 1 year ago

IMO you're both right and I must add that I've copied the CDK's drag-drop package over to a new repo and am working on the stale features I/we need. If you'd like to participate that would be great.

github.com/Recruitler/drag-drop

Finishing nestable drag and drop lists then working on making it an NPM package.

guoliang commented 10 months ago

While waiting, what are everyone else using instead, or can suggest some temporary solution?

louis-lau commented 10 months ago

While waiting, what are everyone else using instead, or can suggest some temporary solution?

I just create another instance of the component while dragging. It's hacky but it works, to the user it looks like it never moves.

guoliang commented 10 months ago

While waiting, what are everyone else using instead, or can suggest some temporary solution?

I just create another instance of the component while dragging. It's hacky but it works, to the user it looks like it never moves.

I was thinking of something like that, cannot get the cloned instance to position where the original was though.

Are you doing similar approach where you create a clone using ViewContainerRef.createComponent?

louis-lau commented 10 months ago

I use dragStarted and dragEnded and store the id of the current item being dragged in a variable. Then in the list I just have the item a second time with an ngif on it, which checks the variable. Nothing fancy and a bit hacky, but it works.

Irina-Intuiface commented 10 months ago

While waiting, what are everyone else using instead, or can suggest some temporary solution?

I'm using a fork of this library https://github.com/Shopify/draggable . Doesn't work with multi-touch though (multiple items being dragged at the same time).

mzalishahzad commented 8 months ago

Any updates on this?

kris-vista commented 5 months ago

Would love to see this implemented, it seems like a no-brainer. My example is I have a "palette" of items that can be dragged to a destination, but each item in the palette can be used as many times as the user wants, e.g. we never want the item to be removed from the source list.

I am using the hack of listning to cdkDropListExited and cdkDropListEntered and adding a dummy item in place of the removed one, but this causes a flicker which is not ideal.

prihafin commented 1 month ago

+1

sychd commented 2 days ago

Another approach for those who are interested: instead of manipulation with elements within the list (in my case I deal with a storage and subscriptions, so I'd like not to trigger that just because of visuals) you can just make a copy of initial container's html to another node. Then show this node and hide initial one. When drag ended, do vice versa - that's it.

Example:

<div
  #dragOriginListEl
  class="list"
  cdkDropList
>
  @for (entry of entries(); track entry.id) {
    <app-list-entry
      cdkDrag
      [cdkDragData]="entry"
      (cdkDragStarted)="dragStarted()"
      (cdkDragEnded)="dragEnded()"
    />
  }
</div>
<div class="drag-active-list list" #dragActiveListEl></div>
.list {
  display: flex;
}
.drag-active-list {
  display: none;
}
 dragActiveListEl = viewChild('dragActiveListEl', {
    read: ElementRef,
  });
  dragOriginListEl = viewChild('dragOriginListEl', {
    read: ElementRef,
  });

  dragStarted() {
    this.copyExistingListNodesToActiveList();
    this.setActiveListVisibility(true);
  }

  dragEnded() {
    this.setActiveListVisibility(false);
  }

  copyExistingListNodesToActiveList() {
    const overlay = this.dragActiveListEl();
    const origin = this.dragOriginListEl();
    if (!overlay || !origin) {
      return;
    }

    overlay.nativeElement.innerHTML = origin.nativeElement.innerHTML;
  }

  setActiveListVisibility(isVisible: boolean) {
    const overlay = this.dragActiveListEl();
    const origin = this.dragOriginListEl();
    if (!overlay || !origin) {
      return;
    }

    overlay.nativeElement.style.display = isVisible ? 'flex' : 'none';
    origin.nativeElement.style.display = !isVisible ? 'flex' : 'none';
  }