ng2-dragula icon indicating copy to clipboard operation
ng2-dragula copied to clipboard

[usage question] Unable to set dragulaModel in drake object in extended directive.

Open razorhenry1 opened this issue 6 years ago • 2 comments

REQUIRED: Before filing a usage question

Change each [ ] to [x] when you have done it.

I am trying to write a angular directive thats extends the dragula directive as, dragula directive cannot work directly on ngx-datatable. I am able to drag row in ngx-datatable, but unable to setup the dragula model for my group . Please help.

Using _: dragula v2 Angular version : 7 PS : drake type is coming up as object, which do not have models[][] array

This is my directive

  import { Directive, OnChanges, AfterViewInit, EventEmitter, OnInit, Output, Input, OnDestroy, 
  ElementRef, SimpleChange } from '@angular/core';
  import { dragula, DragulaService, DrakeWithModels, Group, DrakeFactory } from 'ng2-dragula';
  

 @Directive({ selector: 'ngx-datatable[dragulaName]' })
  export class DragulaExtendedDirective implements OnChanges, OnInit, AfterViewInit, OnDestroy {
  @Input() public dragulaName: string;
  @Input() public dragulaModel: any;
  @Input() public dragulaVScroll: any;
  @Input() public classSelector: string = 'null';
  @Output() public directiveDrop: EventEmitter<any> = new EventEmitter<any>();
  @Output() public directiveDrag: EventEmitter<any> = new EventEmitter<any>();
  
  protected container: any;
  private drake: DrakeWithModels;
  private options: any;
  private el: ElementRef;
  private dragulaService: DragulaService;
  subscriptionDrag: any = null;
  subscriptionDrop: any = null;

  public constructor(el: ElementRef, dragulaService: DragulaService) {
      this.el = el;
      this.dragulaService = dragulaService;
  }
  ngOnInit(){
      
  }

  ngAfterViewInit() {
      if(this.el){
          let container = this.el;
          
          // Check for the row's parent node: datatable-scroller
          // This is what you want to bind Dragula to, in order to drag sort
          if(container.nativeElement.querySelector('datatable-scroller')){
              let rowParent =  container.nativeElement.querySelector('datatable-scroller');
              
              // Check if this Dragula already exists
              if( !this.dragulaService.find(this.dragulaName) ){
                
                  // Must assign the new rowParent as the container you want to pass to Dragula
                  this.container = rowParent;
                  this.initializeDragula();
              }
          }
      }
  }

  ngOnDestroy() {
    
      // Clear this Dragula always
      // comment out if you want to keep it
      if (this.dragulaService.find(this.dragulaName)) {
          this.dragulaService.destroy(this.dragulaName);
      }
      
      // Clear DRAG and DROP subscription to prevent duplicates
      if(this.subscriptionDrag){
          this.subscriptionDrag.unsubscribe();
          this.subscriptionDrag = null;
      }
      if(this.subscriptionDrop){
          this.subscriptionDrop.unsubscribe();
          this.subscriptionDrop = null;
      }
  }

  protected initializeDragula(){
      // Create new Dragula container
      let bag = this.dragulaService.find(this.dragulaName);
      if (bag) {
          this.drake = bag.drake;
          this.checkModel();
          this.drake.containers.push(this.container);
      } else {
          // Check if classSelector was specified
          // *true: 
          //    - the classSelector string will be used to match the class of the element clicked
          //    - the element with the matching class name will be used to drag the row
          // *false: 
          //    - no class selector will be used
          //    - the whole row will default back to being draggable
          if(this.classSelector != 'null'){
              let classSelector = this.classSelector;
              let options = {
                  moves: function (el, container, handle) {
                      return handle.className === classSelector;
                  }
              };
              this.drake = dragula([this.container], options);
          }else{
              this.drake = dragula([this.container]); // drake type is object , which doesn't have access to models array
          }
          this.checkModel();
          let group = new Group(this.dragulaName , this.drake , this.options);
          this.dragulaService.add(group);
      }
      
    //   // Set DRAG and DROP subscriptions and callbacks
      this.subscriptionDrop = this.dragulaService.drop(this.dragulaName).subscribe(({ name ,el ,source , target , sibling}) => {
        this.onDropModel(el , source , target);
      });
  }
  
  private checkModel(){
    this.dragulaService.dropModel(this.dragulaName).subscribe(({ sourceModel, targetModel, item }) => {
        console.log(sourceModel , targetModel , item);
      });
    //   if (this.dragulaModel) {
    //       if (this.drake.models) {
    //           this.drake.models.push([this.dragulaModel]);
    //       } else {
    //           this.drake.models = [this.dragulaModel];
    //       }
    //   }
  }

  private drag(args) {
      let [e, el] = args;
  }

  private onDropModel(el ,source ,target) {
      let shipId = el.firstElementChild.getElementsByClassName("datatable-row-center")[0].firstElementChild.innerText;
      // Added emitter on any DROP action
      this.directiveDrop.emit(this.dragulaModel);
  }

  public ngOnChanges(changes: { dragulaModel?: SimpleChange }): void {
    
    //   Must update model on any changes
    //   Otherwise it will fall out of sync with the 'dragulaModel'
      if (changes && changes.dragulaModel) {
          if (this.drake) {
              if (this.drake.models) { 
                  let modelIndex = this.drake.models.indexOf(changes.dragulaModel.previousValue);
                  this.drake.models.splice(modelIndex, 1, changes.dragulaModel.currentValue);
              } else {
                  this.drake.models = [changes.dragulaModel.currentValue];
              }
          }
      }
  }
}

How do i set dragulaModel in drake object ?

razorhenry1 avatar Mar 07 '19 12:03 razorhenry1

Extending directives is not generally easy or recommended. The precise set of metadata/hooks that the directive uses is not part of the public API. You have to read the source and forward various bindings in the way it expects. That’s all I can really say.

cormacrelf avatar Mar 08 '19 06:03 cormacrelf

The container, in case of ngx-datatable is generated at run-time and hence its impossible to wire dragula directive to the container elements, whose direct child needs to be dragged. That's why I am forced to use a directive. Can you provide any approach of how to add dragula directive at runtime?

razorhenry1 avatar Mar 08 '19 07:03 razorhenry1