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

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();
}
});
};

Related

How to get old and new value of dynamically generated checkbox column in agGrid

I am using agGrid where the columns are dynamically created. My objective is to get the old value and new value after checking the checkboxes. I try to use "onCellValueChanged" but it didnt work. If I use "onCellClicked" then I am not getting Old Value and New Value.
For your understanding I want to mean by Old Value and New Value that if user checked then Old Value is false and New Value is true.
HTML
<ag-grid-angular class="ag-theme-balham" [gridOptions]="siteJobDeptGridOptions"
[rowData]="siteJobDeptRowData" [columnDefs]="siteJobDeptColDef" [paginationPageSize]=10 [domLayout]="domLayout"
(gridReady)="onGridReady($event)">
</ag-grid-angular>
TS File
export class SiteJobDeptConfigComponent implements OnInit {
ngOnInit() {
this.domLayout = "autoHeight";
this.getAllSiteJobConfig();
this.generateColumns();
}
onGridReady(params: any) {
params.api.sizeColumnsToFit();
params.api.resetRowHeights();
}
generateColumns()
{
let deptColDef = [];
let colSiteJob = {
field: 'SiteJobName', headerName: 'Site Job Name',resizable: true,
sortable: true, filter: true, editable: false,
}
this.siteJobDeptCommonService.getEntityData('getpublisheddepts')
.subscribe((rowData) => {
deptColDef.push(colSiteJob);
for(let dept of rowData)
{
deptColDef.push({
field: dept.DeptName, headerName: dept.DeptName, width:100,resizable: true,
cellClass: 'no-border',
cellRenderer : params => {
var input = document.createElement('input');
input.type="checkbox";
input.checked=params.data[dept.DeptName];
return input;
},
onCellValueChanged: this.siteDeptCellValueChanged.bind(this),
})
}
this.siteJobDeptColDef = deptColDef;
},
(error) => { alert(error) });
}
siteDeptCellValueChanged(dataCol: any) {
let checkedOldValue = "Old Check Value - " + dataCol.oldValue;
let checkedNewValue = "New Check Value - " + dataCol.newValue;
}
getAllSiteJobConfig()
{
let siteJobRowData = [];
this.siteJobDeptCommonService.getEntityData('getallsitedeptjob')
.subscribe((rowData) => {
for(let siteJobDetail of rowData)
{
for(let deptAllow of siteJobDetail.DeptAllow)
{
tempArray[deptAllow["DeptName"]] = deptAllow["IsAllow"];
}
siteJobRowData.push(tempArray);
}
this.siteJobDeptRowData = siteJobRowData;
},
(error) => { alert(error) });
}
}
The grid looks like below:-
Can you please help me how to get Old Data and New Data value from checkbox that is dynamically generated?
It should be "cellValueChanged" not "onCellValueChanged" in the column definition creation.
You can find here.
When you declare your method in the params object, there are oldValue and newValue properties that give the result that you are looking for:
onCellValueChanged: function(params) {
console.log(params.oldValue);
console.log(params.newValue)
}

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.

Ag-Grid - Saving columns for future use

I am using the ag-grid for angular1, (and loving it), and I want my users to be able to reorgenize columns, change sortings, and everything, and that it will stay after a refresh.
It should not be very hard, except that the columns are circular (contains pointers to themselves), and thus I cannot parse them.
Code:
var columnDefsKey = "columnDefs["+$rootScope.page+"]";
var savedColumns = localStorage.getItem(columnDefsKey);
function saveColumnsState() {
var currentCol = vm.gridOptions.columnApi.getAllColumns();
if (!angular.equals(currentCol, savedColumns))
try {
localStorage.setItem(columnDefsKey, JSON.stringify(currentCol));
} catch (ex) {
log(ex);
log(currentCol);
}
}
And:
onColumnEverythingChanged: saveColumnsState,
onColumnVisible: saveColumnsState,
onColumnPinned: saveColumnsState,
onColumnResized: saveColumnsState,
onColumnRowGroupChanged: saveColumnsState,
onColumnValueChanged: saveColumnsState,
onColumnMoved: saveColumnsState,
onColumnGroupOpened: saveColumnsState,
It fails on the "try" every time:
TypeError: Converting circular structure to JSON(…) [Column, Column, Column, Column, Column, Column, Column, Column, Column, Column]
How can I do that? (save columns for later use)
If I manage to do that, I will be able to create several views without coding.
you can get the better understanding of the issue from below link
Chrome sendrequest error: TypeError: Converting circular structure to JSON
Also check below reference
https://github.com/isaacs/json-stringify-safe
The way to achieve this was to build my own column model, that I can save and parse again, and in which to save only necessary properties.
This method is XSS vulnerable, as I am evaluating functions, but it is a working solution.
columnsApi: {
key: null,
grid: null,
newColumnModel: {
headerName: "",
width: 200,
valueGetter: "",
filter: 'text',
aggFunc: 'none',
filterParams: {apply: true}
},
setKey: function (key) {
this.key = key;
},
setGrid: function (grid) {
this.grid = grid;
},
format: function (columns) {
var format = [];
angular.forEach(columns, function (col) {
var colDef = {
width: col.actualWidth,
pinned: col.pinned,
hide: !col.visible
};
format.push(angular.extend(col.colDef, colDef));
});
return format;
},
getIDs: function (columns) {
var ids = [];
angular.forEach(columns, function (col) {
ids.push(col.colId);
});
return ids;
},
stringify: function (columns) {
return JSON.stringify(columns, function (key, value) {
if (typeof value === "function")
return "/Function(" + value.toString() + ")/";
return value;
});
},
parse: function (string) {
return JSON.parse(string, function (key, value) {
if (typeof value === "string" &&
value.startsWith("/Function(") &&
value.endsWith(")/")) {
value = value.substring(10, value.length - 2);
return eval("(" + value + ")");
}
return value;
});
},
add: function (column) {
if (this.grid === null) {
console.error("Assertion error: grid must not be null");
return;
}
if(column.aggFunc == 'none')
column.aggFunc = undefined;
var groups = this.get().groups;
var newColumns = this.format(getGridColumns(this.grid));
newColumns.push(column);
this.grid.api.setColumnDefs(newColumns);
this.setGroups(groups);
},
save: function () {
var self = this;
if (this.key === null) {
console.error("Assertion error: key must not be null");
return;
}
if (this.grid === null) {
console.error("Assertion error: grid must not be null");
return;
}
var savedOptions = {
columns: self.format(getGridColumns(self.grid)),
groups: self.getIDs(self.grid.columnApi.getRowGroupColumns()),
sorting: self.grid.api.getSortModel(),
filter: self.grid.api.getFilterModel()
};
localStorage.setItem(this.key, this.stringify(savedOptions));
},
// Get function uses "eval" - XSS vulnerable.
get: function () {
if (this.key === null) {
console.error("Assertion error: key must not be null");
return;
}
var options = localStorage.getItem(this.key);
if (options)
options = this.parse(options);
return options;
},
remove: function (field) {
if (this.grid === null) {
console.error("Assertion error: grid must not be null");
return;
}
var newColumns = this.format(getGridColumns(this.grid));
angular.forEach(newColumns, function (col, key) {
if (col.field == field)
newColumns.splice(key, 1);
});
this.grid.api.setColumnDefs(newColumns);
},
setGroups: function (groups) {
var self = this;
angular.forEach(groups, function (id) {
angular.forEach(getGridColumns(self.grid), function (col) {
if (col.colId == id)
self.grid.columnApi.addRowGroupColumn(col);
});
});
}
}
This solution was written for Ag-Grid 5 I believe, and thus I am not sure if it still holds.

ExtJs - column hide/show state save

I am trying to save state of grid columns,
I set
Ext.state.Manager.setProvider(new Ext.state.CookieProvider());
and configured grid with
stateful: true,
stateId: 'uniqueGridId',
Right now it saves everything about grid, even I do not have stateEvents.
How do I save only column hide / show state?
I tried
initStateEvents : function(){
this.colModel.on('hiddenchange', function(){ this.saveState; });
}
but nothing chages...
Anyway to save hide /show column state and only hide /show column state?
If somebody need it:
applyState: function(state) {
var cs = state.columns;
if (cs.length !== 0) {
for (var i = 0, len = cs.length; i < len; i++) {
var s = cs[i], c = Ext.getCmp(s.id);
if (typeof c !== "undefined") {
if (typeof s.hidden !== "undefined") {
c.hidden = s.hidden;
}
}
}
}
},

ExtJS grid filtering - activating two at the same time

I have the following code to filter a grid from values inputed in a form on a click of a button. The problem is that the first time the filters are activated, only the first filter (displayNameFilter) will be included in the request.
The second time and on, both filters will be included in a request. How can I work around that issue?
var nameFilter = grid.filters.getFilter('name');
if (!nameFilter) {
nameFilter = grid.filters
.addFilter({
type : 'string',
dataIndex : 'name'
});
}
nameFilter.setValue(Ext.getCmp('name-filter').getValue());
var displayNameFilter = grid.filters.getFilter('displayName');
if (!displayNameFilter) {
displayNameFilter = grid.filters
.addFilter({
type : 'string',
dataIndex : 'displayName'
});
}
displayNameFilter.setValue(Ext.getCmp('display-name-filter').getValue());
displayNameFilter.setActive(true, false);
nameFilter.setActive(true, false);
I had a similar problem. The solution is a bit hokey but it works for me, notice that the filter variable is defined a second time within the defer call (it is needed):
grid.filters.createFilters();
var nameFilter = grid.filters.getFilter('name');
if (!nameFilter) {
nameFilter = grid.filters
.addFilter({
type : 'string',
dataIndex : 'name'
});
}
nameFilter.setActive(true);
var displayNameFilter = grid.filters.getFilter('displayName');
if (!displayNameFilter) {
displayNameFilter = grid.filters
.addFilter({
type : 'string',
dataIndex : 'displayName'
});
}
displayNameFilter.setActive(true);
Ext.Function.defer(function() {
nameFilter = grid.filters.getFilter('name');
nameFilter.setValue(Ext.getCmp('name-filter').getValue());
displayNameFilter = grid.filters.getFilter('displayName');
displayNameFilter.setValue(Ext.getCmp('display-name-filter').getValue());
}, 10);
This worked for me:
handler : function() {
var filters = [];
// get filters from a form...
var values = filterForm.getValues();
for (var f in values) {
var value = values[f];
if (value) {
filters.push({ property: f, value: value });
}
}
//...and add all of them to the store used by the grid directly
if (filters.length) {
// prevent events firing here...
gridStore.clearFilter(true);
// ...because they will fire here
gridStore.filter(filters);
} else {
gridStore.clearFilter();
}
}

Resources