PDA

View Full Version : Drag and Drop, Swapping Child Item Positions



melmac
26 Apr 2011, 1:48 AM
Good Day Ext community. I have a problem / quirk with my drag n drop appliction. I have attempted to implement a way for children of certain containers ( be they panels, fieldsets, fields) to be swapped inside their parent container i.e. changing their order. However I noticed that when I attempt to swap an element in the same panel the dragged panel disappears. It exists in the DOM and in the parent panel, but its not displayed, that is it has not been inserted ahead of or behind its sibling container.


<script type="text/javascript">

Ext.onReady(function(){

var proxyOverrides = {
startDrag : function()
{

var dragProxy = Ext.get(this.getDragEl());
var dragEl = Ext.get(this.getEl());
dragProxy.setStyle('z-index','10000');
dragProxy.setOpacity(.70);
dragProxy.update(dragEl.dom.innerHTML);
dragProxy.setSize(dragEl.getSize());
this.originalXY = dragEl.getXY();

},
onDragEnter : function(evtObj, targetElId)
{
var targetEl = Ext.getCmp(targetElId);
targetEl.body.highlight();
},
onDragOut : function(evtObj, targetElId)
{
},
onInvalidDrop : function()
{
this.invalidDrop = true;
},
onDragDrop: function(evtObj, targetElId)
{

var dragEl = Ext.getCmp(this.getEl().id);
var dropEl = Ext.getCmp(targetElId);

var insertAhead = false;
var dragProxy = Ext.get(this.getDragEl());


// if the panel is dragproxy is in the first half of the dropel panel place infront, otherwise ...
if(dragProxy.getXY()[0] <= dropEl.getPosition()[0] + (dropEl.getWidth()/2))
{
insertAhead = true;
}

//remove dragEl from parent so that it can be added again in new index. Layout manager should reorganise child items?
dragEl.ownerCt.remove(dragEl, false);
//dropEl.ownerCt.doLayout();

//either insert the dragEl into the index (pushing the dropEl back) 1 or index +1
var index = insertAhead ? dropEl.ownerCt.items.items.indexOf(dropEl) : dropEl.ownerCt.items.items.indexOf(dropEl) + 1;

///console.log('dropEl', dropEl.ownerCt.items.items.indexOf(dropEl), 'length', dropEl.ownerCt.items.items.length, 'index' ,index);

dropEl.ownerCt.insert(index, dragEl);
view.doLayout();

///console.log('dropEl', dropEl.ownerCt.items.items.indexOf(dropEl), 'dragEl', dropEl.ownerCt.items.items.indexOf(dragEl), 'length', dropEl.ownerCt.items.items.length);

},
b4EndDrag : Ext.emptyFn,

endDrag : function()
{
var dragProxy = Ext.get(this.getDragEl());
if (this.invalidDrop === true)
{
var dragEl = Ext.get(this.getEl());
var animCfgObj =
{
easing: 'easeOut',
duration : 1,
callback : function()
{
dragProxy.hide();
dragEl.highlight();

if(dragEl.ownerCt){dragEl.ownerCt.doLayout();}
}
}
dragProxy.moveTo(this.originalXY[0], this.originalXY[1], animCfgObj);
}
else
{
dragProxy.hide();
}
delete this.invalidDrop;
}
};

var panel1 = {
xtype : 'panel',
title: 'Panel1',
height: 300,
listeners:{
render: function()
{
new Ext.dd.DDTarget(this.el, 'panel2');

var dragField = new Ext.dd.DDProxy(this.el, 'panel1');
Ext.apply(dragField, proxyOverrides);
}
},
items:[{xtype: 'textfield'}]
};

var panel2 = {
xtype: 'panel',
title: 'Panel2',
height: 300,
listeners:{
render: function()
{
new Ext.dd.DDTarget(this.el, 'panel1');

var dragField = new Ext.dd.DDProxy(this.el, 'panel2');
Ext.apply(dragField, proxyOverrides);
}
},
items:[]
};

var view = new Ext.Viewport({
renderTo : Ext.getBody(),
layout: 'hbox',
defaults: {flex: 1},
items:[panel1, panel2]
});


});</script>

My example here is of two panels, which can be swapped. It should work that if one is dragged more than half the length of the other, they sway positions. The issue usually occurs when I attempt to drag panel 2 ahead of panel 1, but I can't understand why.

Any help would be greatly appreciated

melmac
27 Apr 2011, 12:25 AM
It appears to be nothing to do with drag n drop. Here is another example (based on the above) with buttons to swap two panels in the viewport.

The same happens. It works once '1->2', but after that not.


Ext.onReady(function(){

var panel1 = {
xtype : 'panel',
title: 'Panel1',
height: 300,
items:[{xtype: 'textfield'}]
};

var panel2 = {
xtype: 'panel',
title: 'Panel2',
height: 300,
items:[]
};

var buttons = {
xtype: 'container',
items: [{
xtype: 'button',
text: '1 <- 2',
listeners:{
click: function()
{
//panel to be moved. right panel
var mover = view.items.items[1];

//remove from parent and reinsert into position
view.remove(mover, false);

//view.doLayout();
view.insert(0, mover);

view.doLayout();
}
}
},{
xtype: 'button',
text: '1 -> 2',
listeners:{
click: function()
{
//panel to be moved. left panel
var mover = view.items.items[0];

//remove from parent and reinsert into position
view.remove(mover, false);

//view.doLayout();
view.insert(1, mover);

view.doLayout();
}
}
}]
}

var view = new Ext.Viewport({
renderTo : Ext.getBody(),
layout: 'hbox',
defaults: {flex: 1},
items:[panel1, panel2, buttons]
});


});

melmac
27 Apr 2011, 1:30 AM
The issue is apparently a design omission, not a bug.

http://www.sencha.com/forum/showthread.php?27640-How-to-change-items-order-in-Panel

Though as jedik points out, it seems silly to have a half implemented insert mechanism, i.e no reordering of previously rendered child items.

I'll be attempting to work on a solution to this myself, but if anyone has any pearls of wisdom that could help me along, that would be greatly appreciated

melmac
27 Apr 2011, 4:13 AM
Foud this bug thread:

http://www.sencha.com/forum/showthread.php?89291-CLOSED-3.-Container.insert(index-comp)-rendering-issue&highlight=destroyed+component&langid=1

Animal's advice worked for me:


this.remove(oldComp, false);
var d = oldComp.getPositionEl().dom;
d.parentNode.removeChild(d);
this.insert(new-index, oldComp);
this.doLayout();

I hope someone else finds this helpful