Extjs - drag drop restriction - extjs

How do I restrict the drag operation not exceeding certain boundary. Is there any config in extjs (version 3), I saw that, Ext.dd.DragZone class is used. But Im not sure what is the usability. I saw a method dropNotAllowed. Is that the method, that has to be used? if so, how should I use that? Please provide some examples.
Im looking for something similar to (jquery UI's draggable containment property)
http://docs.sencha.com/extjs/3.4.0/#!/api/Ext.dd.DragZone-cfg-dropNotAllowed
I tried using the set X and Y constraints, but it did not work-out:
abc.prototype.initDrag = function(v) {
v.dragZoneobj = new Ext.dd.DragZone(v.getEl(), {
getDragData : function(e) {
var sourceEl = e.getTarget(v.itemSelector, 10);
// sourceEl.setXConstraint( 0, 10 );
var t = e.getTarget();
var rowIndex = abc.grid.getView().findRowIndex(t);
var columnIndex = abc.grid.getView().findCellIndex(t);
if ((rowIndex !== false) && (columnIndex !== false)) {
if (sourceEl) {
abc.isDragged = true;
abc.scriptGrid.isDraggableForObject = false;
abc.scriptGrid.dragRowIndex = false;
d = sourceEl.cloneNode(true);
d.id = Ext.id();
d.textContent = sourceEl.innerHTML;
// d.setXConstraint( 0, 10 );
// d.setYConstraint( 0, 10 );
return {
ddel : d,
sourceEl : d,
sourceStore : v.store
}
}
}
},
getRepairXY : function() {
return this.dragData.repairXY;
},
});
}
Both are commented in the above code. The above code is initiated when the panel is rendered.
edit:
How these setX and setYcontraints have to be used?

By default, the element can be dragged any place on the screen. In the doc there are two methods setXConstraint( iLeft, iRight, iTickSize) and setYConstraint( iUp, iDown, iTickSize )
These two methods is used to set to limit the vertical travel and horizental travel of the element.

Related

Fieldcontainer incorrectly displays in toolbar with label aligned top

FieldContainer doesn't show correctly when you put labelAlign: 'top'.
Find my Fiddle : https://fiddle.sencha.com/#fiddle/1c2s
I create a custom field which is base on field container.
If you resize the window to a smaller size, you'll see that the textfield will go above the fieldContiner.
Any idea on how to fix this? Any workaround?
I've tried several stuff but I'm struggling... I don't now where I can act to change this...
And I definitly need to fix this.
Thanks in advance
(for reference: Open bug in Sencha forum: https://www.sencha.com/forum/showthread.php?311212-Fieldcontainer-incorrectly-displays-in-toolbar-with-label-aligned-top)
Looks like bug indeed, but there is pretty easy way to make that work - just set minHeight: 65 to your url field.
Fiddle: https://fiddle.sencha.com/#fiddle/1caa
I'm pretty sur I found the answer.
There is a mismatch between the build src and the doc!
If you check in your built source for file src/layout/component/field/FieldContainer.js you will notice that it doesn't correspond to the doc (and especially some method missing like calculateOwnerHeightFromContentHeight).
note: This has been fixed in ExtJs 6.2.0
Proposed override to fix this:
/**
* Override to fix componentLayout wrong calculation of height when labelAlign='top'
*
* See post forum:
* {#link https://www.sencha.com/forum/showthread.php?311212-Fieldcontainer-incorrectly-displays-in-toolbar-with-label-aligned-top}
*/
Ext.define('MyApp.overrides.layout.component.field.FieldContainer', {
override: 'Ext.layout.component.field.FieldContainer',
compatibility: [
'6.0.0',
'6.0.1',
'6.0.2'
],
/* Begin Definitions */
calculateOwnerHeightFromContentHeight: function(ownerContext, contentHeight) {
var h = this.callSuper([ownerContext, contentHeight]);
return h + this.getHeightAdjustment();
},
calculateOwnerWidthFromContentWidth: function(ownerContext, contentWidth) {
var w = this.callSuper([ownerContext, contentWidth]);
return w + this.getWidthAdjustment();
},
measureContentHeight: function(ownerContext) {
// since we are measuring the outer el, we have to wait for whatever is in our
// container to be flushed to the DOM... especially for things like box layouts
// that size the innerCt since that is all that will contribute to our size!
return ownerContext.hasDomProp('containerLayoutDone') ? this.callSuper([ownerContext]) : NaN;
},
measureContentWidth: function(ownerContext) {
// see measureContentHeight
return ownerContext.hasDomProp('containerLayoutDone') ? this.callSuper([ownerContext]) : NaN;
},
publishInnerHeight: function(ownerContext, height) {
height -= this.getHeightAdjustment();
ownerContext.containerElContext.setHeight(height);
},
publishInnerWidth: function(ownerContext, width) {
width -= this.getWidthAdjustment();
ownerContext.containerElContext.setWidth(width);
},
privates: {
getHeightAdjustment: function() {
var owner = this.owner,
h = 0;
if (owner.labelAlign === 'top' && owner.hasVisibleLabel()) {
h += owner.labelEl.getHeight();
}
if (owner.msgTarget === 'under' && owner.hasActiveError()) {
h += owner.errorWrapEl.getHeight();
}
return h + owner.bodyEl.getPadding('tb');
},
getWidthAdjustment: function() {
var owner = this.owner,
w = 0;
if (owner.labelAlign !== 'top' && owner.hasVisibleLabel()) {
w += (owner.labelWidth + (owner.labelPad || 0));
}
if (owner.msgTarget === 'side' && owner.hasActiveError()) {
w += owner.errorWrapEl.getWidth();
}
return w + owner.bodyEl.getPadding('lr');
}
}
});

Extjs - drag drop restriction, containment

In Extjs, I want to know whether I can restrict the dragging of elements within a specific x,y co-ordinates, just like an option, containment in jQuery-UI.
Currently this is my code:
abc.prototype.initDrag = function(v) {
v.dragZone = new Ext.dd.DragZone(v.getEl(), {
containerScroll : false,
getDragData : function(e) {
var sourceEl = e.getTarget(v.itemSelector, 10);
var t = e.getTarget();
var rowIndex = abc.grid.getView().findRowIndex(t);
var columnIndex = abc.grid.getView().findCellIndex(t);
var abcDragZone = v.dragZone ; //Ext.getCmp('idabcDragZone');
var widthToScrollV = $(window).width()-((columnIndex-1)*100);
var widthToScrollH = $(window).height()-((5-rowIndex)*30);
abcDragZone.setXConstraint(0,widthToScrollV);
abcDragZone.setYConstraint(widthToScrollH,0);
if ((rowIndex !== false) && (columnIndex !== false)) {
if (sourceEl) {
abc.isDragged = true;
def.scriptGrid.isDraggableForObject = false;
def.scriptGrid.dragRowIndex = false;
d = sourceEl.cloneNode(true);
d.id = Ext.id();
d.textContent = "\$" + abc.grid.getColumnModel().getColumnHeader(columnIndex);
return {
ddel : d,
sourceEl : d,
sourceStore : v.store
}
}
}
},
getRepairXY : function() {
return this.dragData.repairXY;
},
});
}
But the problem is that the initdrag is called when the csv sheet is added to DOM. Only when its added that element can be accessed and the individual cells' drag limits can be set. So once I add a csv, the limits are not getting set. If I add it again to DOM then the limits work. Is there an option like the jQuery UI containment for draggable, here in extjs?
edit:
I even tried :
constrainTo( constrainTo, [pad], [inContent] )
body had an id of #abc
when I tried with
dragZoneObj.startDrag = function(){
this.constrainTo('abc');
};
which is a method of the DragZone class. It still did not cover the whole body tag.

customizing ag-grid to set a max number of selectable rows

I am trying to customize a data table using ag-grid in my Angular 1.5 based project. The customization is that the user is allowed to select a maximum number of rows in the table, for example, the maximum is 2.
I have the following code by using node.setSelected(false) that I found in the documentation page here, but I got the error: node.setSelected is not a function when the selection exceeds the maximum of 2.
var gridOptions = {
columnDefs: columnDefs,
rowSelection: 'multiple',
onRowSelected: onRowSelected
};
function onRowSelected(event) {
var curSelectedNode = event.node;
var selectionCounts = vm.gridOptions.api.getSelectedNodes().length;
if (selectionCounts > 2) {
var oldestNode = vm.gridOptions.api.getSelectedNodes()[0]; // get the first node, to be popped out
oldestNode.setSelected(false); // causes the above 'not a function' error
}
}
Does anyone know what might be wrong with ag-grid for its setSelected() API? or any better way to do this customization?
it turns out that setSelected(false) method is outdated in its current ag-grid API, and I found that I can use deselectIndex() method to deselect the oldest node:
if (selectionCounts > 2) {
vm.gridOptions.api.deselectIndex(0, true); // This works!
}
Hope this will help someone else in the future!
var columnDefs =[{
headerName: 'Name',
field: 'name',
width: 108,
minLength: 1,
maxLength: 20,
editable: true
}]
- Modify prototype in file .js
TextCellEditor.prototype.init = function (params) {
var eInput = this.getGui();
var startValue;
// Set min & max length
if (params.column.colDef.maxLength)
eInput.maxLength = params.column.colDef.maxLength;
if (params.column.colDef.minLength)
eInput.minLength = params.column.colDef.minLength;
// cellStartedEdit is only false if we are doing fullRow editing
if (params.cellStartedEdit) {
this.focusAfterAttached = true;
var keyPressBackspaceOrDelete = params.keyPress === constants_1.Constants.KEY_BACKSPACE
|| params.keyPress === constants_1.Constants.KEY_DELETE;
if (keyPressBackspaceOrDelete) {
startValue = '';
}
else if (params.charPress) {
startValue = params.charPress;
}
else {
startValue = params.value;
if (params.keyPress !== constants_1.Constants.KEY_F2) {
this.highlightAllOnFocus = true;
}
}
}
else {
this.focusAfterAttached = false;
startValue = params.value;
}
if (utils_1.Utils.exists(startValue)) {
eInput.value = startValue;
}
this.addDestroyableEventListener(eInput, 'keydown', function (event) {
var isNavigationKey = event.keyCode === constants_1.Constants.KEY_LEFT || event.keyCode === constants_1.Constants.KEY_RIGHT;
if (isNavigationKey) {
event.stopPropagation();
}
});
};

Ext JS EditorGridPanel - How to split cell to show multiple rows

In Ext.grid.EditorGridPanel table how to split a cell to have two or three rows?
Like the below image
I managed to do a kind of rowspan instead of row splitting. IMO it's easier and it looks the same as grid on attached image. Example code:
var grid = new Ext.grid.EditorGridPanel({
[...],
// hook up events
initComponent: function () {
Ext.grid.GridPanel.prototype.initComponent.call(this);
this.getView().on('refresh', this.updateRowSpan, this);
this.getView().on('rowupdated', this.updateRowSpan, this);
},
onLayout : function(vw, vh) {
this.updateRowSpan();
},
// set span on rows
updateRowSpan: function() {
var columns = this.getColumnModel().config,
view = this.getView(),
store = this.getStore(),
rowCount = store.getCount(),
column = columns[0], // put propert column index here
dataIndex = column.dataIndex,
spanCell = null,
spanCount = null;
spanValue = null;
for (var row = 0; row < rowCount; ++row) {
var cell = view.getCell(row, 0),
record = store.getAt(row),
value = record.get(dataIndex);
if (spanValue != value) {
if (spanCell !== null) {
this.setSpan(Ext.get(spanCell), spanCount);
}
spanCell = cell;
spanCount = 1;
spanValue = value;
} else {
spanCount++;
}
}
if (spanCell !== null) {
this.setSpan(Ext.get(spanCell), spanCount);
}
},
// set actual span on row
setSpan: function(cell, count) {
var view = this.getView(),
innerCell = Ext.get(cell.down('*')),
height = cell.getHeight(),
width = cell.getWidth();
cell.setStyle('position', 'relative');
if (count == 1) {
innerCell.setStyle('position', '');
innerCell.setStyle('height', '');
innerCell.setStyle('height', '');
} else {
innerCell.setStyle('position', 'absolute');
innerCell.setStyle('height', (height * count - cell.getPadding('tb') - innerCell.getPadding('tb')) + 'px');
innerCell.setStyle('width', (width - cell.getPadding('lr') - innerCell.getPadding('lr')) + 'px');
}
}
});
This code changes style of .x-grid3-cell-inner by applying position: absolute and big enough size to cover rows below. Notice that you must also apply some opaque background to make it work. Working sample: http://jsfiddle.net/RpxZ5/8/
I first wrote code for Ext JS 4, if you interested, here is working sample: http://jsfiddle.net/wQSQM/3/

How to get the minimal required width for a dijit ComboBox or FilteringSelect?

I'm using ComboBox and FilteringSelect in a dialog and have yet been unable to make the controls have the minimal required width only, i.e. being just large enough to display the longest text from a drop-down list. Also the control must not be set to a fixed width since the actual content of the drop-down lists gets filled in from a translation database.
In plain html with a simple input of type text it works smooth just by default. However since even all examples at dojotoolkit.org show the very same behavior it seems to me that dojo introduces a minimum width for all those input controls. Thus I wonder if it can be done at all...
Thanks in advance!
I had the same problem; after some struggle, I decided to adapt this to my problem.
In my case, I was forced to use an old version of dojo, and the FilteringSelect were declarative, so I had to use a hack (the last three lines of the code below) to be sure my function would be executed at the right time.
So, the function below takes all dijit widgets, looks for those stored element is a select (getAllDropdowns), and for each it takes its options, copies the content in a new element moved outside of the visible screen and takes the width of that element, adjusted with padding (this may not be your case, so check getWidth); then it takes the max of those widths and compare it with the current length of the input element, and if the longest option is bigger, adjust the input and the outmost div widths.
This answer comes quite late, but since it was not easy for me to come to this solution, I thought it may be worth sharing.
// change dropdowns width to fit the largest option
function fixDropdownWidth() {
var getAllDropdowns = function() {
var dropdowns = [];
dijit.registry.forEach(function(widget, idx, hash) {
if (widget.store) {
var root = widget.store.root;
if (root && root.nodeName.toLowerCase() == 'select') {
dropdowns.push(widget);
}
}
});
return dropdowns;
};
var getTesterElement = function() {
var ret = dojo.query('tester');
if (ret.length) {
return ret;
}
else {
document.body.appendChild(document.createElement('tester'));
return dojo.query('tester');
}
};
var getWidth = function(el) {
var style = dojo.getComputedStyle(el);
return el.clientWidth + parseInt(style.paddingLeft) + parseInt(style.paddingRight);
};
var getOptionWidth = function(option) {
var testEl = getTesterElement();
testEl[0].innerHTML = option.innerHTML;
return getWidth(testEl[0]);
};
var dropdowns = getAllDropdowns();
var testEl = getTesterElement();
dojo.style(testEl[0], {
position: 'absolute',
top: -9999,
left: -9999,
width: 'auto',
whiteSpace: 'nowrap'
});
for (var i = 0; i < dropdowns.length; i++) {
var input = dropdowns[i].textbox;
dojo.style(testEl[0], {
fontSize: dojo.style(input, 'fontSize'),
fontFamily: dojo.style(input, 'fontFamily'),
fontWeight: dojo.style(input, 'fontWeight'),
letterSpacing: dojo.style(input, 'letterSpacing')
});
var max = 0;
var treshold = 5;
dojo.query('option', dropdowns[i].store.root).forEach(function(el, idx, list) {
max = Math.max(max, getOptionWidth(el) + treshold);
});
if (max > getWidth(dropdowns[i].textbox)) {
var icon = dojo.query('.dijitValidationIcon', dropdowns[i].domNode)[0];
dojo.style(dropdowns[i].textbox, {width: max + 'px'});
var width = max + getWidth(icon) + getWidth(dropdowns[i].downArrowNode) + treshold;
dojo.style(dropdowns[i].domNode, {
width: width + 'px'
});
}
}
}
dojo.addOnLoad(function() {
dojo._loaders.push(fixDropdownWidth);
});
var dropDowns = [];
var getAllDropdowns = function (dropDowns) {
array.forEach(dijit.registry.toArray(), function (widget) {
if (widget.store) {
if (widget.domNode.classList.contains("dijitComboBox")) {
dropDowns.push(widget);
}
}
});
};
getAllDropdowns(dropDowns);
var maxLength = 0;
array.forEach(dropDowns, function (dropDown) {
var opts = dropDown.get("store").data;
array.forEach(opts, function (option) {
var optionValue = option[dropDown.get("searchAttr")];
var dropDownCurrentStyle = window.getComputedStyle(dropDown.domNode);
var currentOptionWidth = getTextWidth(optionValue, dropDownCurrentStyle.fontStyle, dropDownCurrentStyle.fontVariant, dropDownCurrentStyle.fontWeight, dropDownCurrentStyle.fontSize, dropDownCurrentStyle.fontFamily);
if (currentOptionWidth > maxLength) {
maxLength = currentOptionWidth;
}
});
dropDown.domNode.style.width = maxLength + "px";
maxLength = 0;
});
function getTextWidth(text, fontStyle, fontVariant, fontWeight, fontSize, fontFamily) {
// re-use canvas object for better performance
var canvas = getTextWidth.canvas || (getTextWidth.canvas = document.createElement("canvas"));
var context = canvas.getContext("2d");
var font = fontStyle + " " + fontVariant + " " + fontWeight + " " + fontSize + " " + fontFamily;
context.font = font;
canvas.innerText = text;
var metrics = context.measureText(text);
return metrics.width + 25; //change this to what you need it to be
}

Resources