7

I have a Angular2 component using ng2-dragula to drag/drop like this:

@Component({
  selector: 'my-comp',
  directives: [
    Dragula
  ],
  viewProviders: [
    DragulaService
  ],
  template: `
    <div class="my-div">
      <div *ngFor="#item of items" [dragula]='"card-bag"' [dragulaModel]='items'>
      ...
      </div>
    </div>
  `
})

My issue: if I create multiple "my-comp" component, item inside "card-bag" can not drag/drop across these component although they have the same bag name. These item are only able to drag/drop inside it owned component.

Do we have any configs for drag/drop across components, or this is ng2-dragula limitation?

Thanks.

qnreck
  • 73
  • 1
  • 6
  • Hopefully someone else can chime in but I think you would have to make this a global service within bootstrap to get that kind of functionality. The problem is when you import this within each component seperately, it makes a new instance of it for each component. If you add it to your bootstrap it is a global attachment for all of your components. I hope this answers what you were asking about! – Morgan G Mar 14 '16 at 07:13
  • @MorganG: thank you. I also think about that idea, but I hope we will have an official or a better solution for this problem.. – qnreck Mar 14 '16 at 17:45
  • One way I made a work around for this, is I have a service that's a global variable with a list of observables and I just reference that observable or object every time I need it in other pieces of my application. Whenever I need another global observable or object I just add it to that service. But I agree it seems a bit backwards to have to do everything that way. – Morgan G Mar 14 '16 at 20:40
  • @MorganG can you elaborate on this with a bit of code? I am trying to do the same, but can't figure out how to get it globally. – henk Mar 24 '16 at 13:36
  • @MorganG do u have any plnkr for this? i have this problem to except I have thumbnails of components and I want load corresponding components on dragging of thumbnails – Bhushan Gadekar Apr 28 '16 at 10:53
  • @BhushanGadekar so I have not actually had to do many animation style things within Angular2 they stated they are still working on coming up with good solutions for it. That's the last major piece that's going to come out. The question was specifically how to make a component a global component, is that your kind of problem as well? – Morgan G Apr 28 '16 at 16:25
  • @MorganG No actually I have one global component which has few other components as directives .i.e. left-sidebar and layout component. I have listed thumbnails of my few components in left-sidebar and i want to drag these thumbnails inside layout component as components.but left-sidebar and layout are different components so i was not sure how to use ng2-dragula to make this happen? do you have any working example for such scenario? – Bhushan Gadekar Apr 28 '16 at 16:37
  • @BhushanGadekar so I think you should probably ask this on Stack Overflow but if it was me I would have a component wrap those other two components and have drag/drop triggers, there really is not a good solution for this because of how components work currently. I would certainly ask this on Stack Overflow as I am not the best person to ask about this and someone better than me has probably already figured this out. I am sorry I can't help more! Good luck. – Morgan G Apr 28 '16 at 16:55
  • @MorganG if u are gonna ask this anywhere then notify me about that...so i ll also be able to track that..kudos – Bhushan Gadekar Apr 28 '16 at 18:34
  • @qnreck did you get a working solution for this? I've tried making dragula global by using the angular2 UpgradeAdaptor addProvider method. But so far its not working. – jhulme May 19 '16 at 15:51

2 Answers2

10

If you are not using [dragulaModel] then drag and drop between nested components works well as long as you only set viewProviders: [ DragulaService ] once in the top/root component.

Remember not to set viewProviders: [ DragulaService ] in other components as it creates new instances for every component.

Edit: Recently I have implemented the given scenario using ng2-dnd npm package. Its better than ng2-dragula and offers easy object passing and other things. It might Solve your issue.

Bhushan Gadekar
  • 12,317
  • 20
  • 77
  • 124
  • Thanks for the ng2-dnd mention, that is a great find, easy to use, works great! – rmcsharry Dec 20 '16 at 09:53
  • Thanks , the ng2-dnd rocks , my whole requirement was to have an ability to carry data across droppable and draggable divs , ng2-dnd is perfect for that , I would recommend anyone dnd over dragula. – pritesh agrawal Jul 11 '17 at 01:57
2

I got a tree structure drag and drop working like this:

Top level component

  • CSS ViewEncapsulation.None, include any css here
  • Dragula Directive
  • DragulaService ViewProvider
  • Registering an accepts filter on the dragula service that stops items from being dropped inside themselves

    accepts: (el: Element, target: Element, source: Element, sibling: Element): boolean => {
     return !el.contains(target); // elements can not be dropped within themselves
    },
    
  • Registering a moves filter on the dragula service so that an entire item is moved together

    moves: (el: Element, container: Element, handle: Element): boolean => {
      // only move favorite items, not the icon element
      return el.tagName.toLowerCase() === 'mvp-navigation-item';
    },
    
  • Html template looks like this

    <div class="nav--favorites__root" [class.is-dragging]="isDragging" [dragula]="'favorites'" [dragulaModel]="favoriteLinks">
      <navigation-item *ngFor="let link of links" [link]="link">
      </navigation-item>
    </div>
    

Navigation item component

  • Dragula Directive
  • No DragulaService ViewProvider
  • Html template looks like this

    <a href class="list-group-item" linkActive="active" [linkTo]="link?.url" (click)="followLink($event, link)">
      <span class="glyphicon glyphicon-{{link?.icon ? link?.icon : 'unchecked'}}"></span>
      <span class="nav__label">{{link?.label}}</span>
    </a>
    <div *ngIf="link?.children" class="list-group list-group-inverse nav--favorites__submenu" [class.is-expanded]="link?.isExpanded" [class.is-empty]="link?.children?.length === 0" [dragula]="'favorites'" [dragulaModel]="link?.children">
      <navigation-item *ngFor="let childLink of link?.children" [link]="childLink">
      </navigation-item>
      <!-- the nav favorites items must be the first elements in the dragula container or the model sync gets confused -->
      <a class="btn btn-link toggle" (click)="link.isExpanded = !link.isExpanded; $event.preventDefault();"><span class="glyphicon glyphicon-triangle-{{link?.isExpanded ? 'top' : 'bottom'}}"></span></a>
    </div>
    

You'll need to style things to make the .nav--favorites__submenu visible as a drop target while dragging an item.

Isaac
  • 2,003
  • 10
  • 15
  • No Dragula directive in the child dragula throws error something like 'Dragula is not a native property'. It cannot launch any tag with [dragula] since no directives are specified. Not sure if your answer is right, I think not. – Becario Senior Sep 01 '16 at 12:05
  • 2
    @BecarioSenior after RC5, directives are declared in the ngModule instead of the individual components. Besides that change, everything still works. Make sure that the DragulaService is declared in the top component or in the ngModule but not in the child components, since we want a single shared instance of the service. – Isaac Sep 01 '16 at 17:31
  • Didn-t know that,Thank you! – Becario Senior Sep 02 '16 at 22:59
  • This one work for me, but I can't find any way to drag for example 2 next items together. I have select mode, but I didn't have any idea how keep it together during drag mode... – kris_IV Jan 16 '19 at 14:37