[usage question] Unable to set dragulaModel in drake object in extended directive.
REQUIRED: Before filing a usage question
Change each [ ] to [x] when you have done it.
- [x] My issue title starts with
[usage question] - [x] I have read the README, especially the 'classic blunders' section
- [x] I have looked at the demos to see if my use case has obvious examples.
- [x] I have searched the
ng2-dragulaissues, including closed issues. - [x] I have browsed the issues labeled "future reference" for problems that have been solved before.
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 ?
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.
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?