This question is actually sort of simple, but: Is it possible to sort a DataTable on more than one column?
So that the user can decide if it should be sorted on for example Name or Year?
If possible how do you implement it?
you can use onSort in every column like this
DataColumn(
label: Text('name'),
onSort: (columnIndex, sortAscending) {
setState(() {
if (columnIndex == _sortColumnIndex) {
_sortAsc = _sortNameAsc = sortAscending;
} else {
_sortColumnIndex = columnIndex;
_sortAsc = _sortNameAsc;
}
_persons.sort((a, b) => a.name.compareTo(b.name));
});
},
),
Related
I am trying to save PivotGrid state for future load. I have two problems
1: the expand property of row items is not changed at run time. Test here https://dojo.telerik.com/#Mzand/obIkEdAY : When the user expands an item at runtime the expand property of the returned row by dataSource.rows() is the same as what it was at initialization.
2: I can't find a way to save/load the selected feilds (slices) using the "Fields to Include" menu along side with rows,columns and measures.
I'm working in React but you should be able to do something similar.
This is a bug, to work around it you can listen to expandMember and collapseMember events to manually track the axis and path of expanded rows/columns. see code below.
If you mean the Configurator, just set its dataSource to that of the pivot grid after you create it. See below in createGrid().
Bonus, see the end of createGrid to auto expand the items in the Configurator.
createGrid = () => {
$(`#pivot-grid`).kendoPivotGrid({
dataSource: {
data: data,
schema: schema,
columns: this.state.columns,
rows: this.state.rows,
measures: this.state.measures,
filter: this.state.filter
},
expandMember: this.onExpand,
collapseMember: this.onCollapse
});
let grid = $(`#pivot-grid`).data('kendoPivotGrid');
if (grid) {
if (this.state.expands) {
this.state.expands.forEach(expand => {
if (expand.axis === 'rows') {
grid.dataSource.expandRow(expand.path);
} else {
grid.dataSource.expandColumn(expand.path);
}
});
}
$(`#pivot-config`).kendoPivotConfigurator({
dataSource: grid.dataSource,
filterable: true
});
}
// Expand the items in the configurator fields.
let tree = $('.k-treeview').data('kendoTreeView');
if (tree) {
tree.expand('.k-item');
}
};
onExpand = e => {
this.setState({
expands: [...this.state.expands, {
axis: e.axis,
path: e.path
}]
});
};
onCollapse = e => {
this.setState({
expands: this.state.expands.filter(ex => ex.axis !== e.axis && JSON.stringify(ex.path) !== JSON.stringify(e.path))
});
};
Here is my try on this
what i like is, that it actually updates the data source as you would expect
function onExpandOrCollapseMember(e, expand) {
var pivot = e.sender;
var axisToUpdate = '_' + e.axis;
var field = _.find(pivot.dataSource[axisToUpdate], f => JSON.stringify(f.name) === JSON.stringify(e.path));
field.expand = expand;
}
And on the pivot options i pass in
expandMember: e => onExpandOrCollapseMember(e,true),
collapseMember: e => onExpandOrCollapseMember(e, false),
I am using custom multi-select code to filter a column. Currently I can get it to filter based on one selection, but am unable to filter based on multiple values. I need the logic to read, if any of the selected checkboxes are checked, then show the selections in the grid. The way I have it written right now, its filtering each one, but if one of the selections is false, it deletes it from the grid even if one of the other selections are true.
var filter = dataSource.filter() || { logic: "or", filters: [] };
var fieldFilters = $.map(element.find(":checkbox:checked"), function (input) {
return {
field: field,
operator: "eq",
value: input.value
};
});
if (fieldFilters.length) {
removeFiltersForField(filter, field);
filter.filters.push({
logic: "or",
filters: fieldFilters
});
var filterType = filter.filters[0].filters;
if (filter.filters[0].filters.length > 1) {
var filterLogic = { logic: "or", filters: filter.filters };
dataSource.filter(filterLogic.filters[0]);
} else {
dataSource.filter(filterType); // This works, but its only one selection
}
}
I need it to return if any selections are true and ignore the ones that are false. Currently, it goes in order, so if the first selection is true, it shows it in the grid, but if the next one is false, then it removes it from the grid.
OK I was able to make it work doing this. If someone has a more efficient way to do it, add it here. For now, this works:
var multipleFilters = [];
if (filterType.length > 1) {
$(filterType).each(function (i, value) {
var simpleFilter = { field: value.field, operator: value.operator, value: value.value };
multipleFilters.push(simpleFilter);
})
if (multipleFilters == 2) {
dataSource.filter(multipleFilters[0] || multipleFilters[1]);
} else if (multipleFilters == 3) {
dataSource.filter(multipleFilters[0] || multipleFilters[1] || multipleFilters[2]);
} else {
dataSource.filter(multipleFilters[1] || multipleFilters[2] || multipleFilters[3]);
}
} else {
dataSource.filter(filterType);
}
is it possible to have comboboxes (dropdowns) on a row rather than a column?
all the examples I've found talk about columns only, e.g.
http://docs.handsontable.com/0.15.0-beta6/demo-dropdown.html
I need a row of editable comboboxes instead, does anyone have any examples of how do achieve this, if it is even possible?
Yes what you want to do is use the cells option just like you would the columns. In this one you are supplied with row,col so you would do something like:
cells: function(row,col) {
if (row == 0) {
// checkbox logic
}
}
And that should be all!
JsFiddle with example
#ZekeDroid pointed me in the right direction to the answer for what I actually asked. Adding the code here so you don't have to waste time learning to do it for yourself.
function getCarData() {
return [
['dog', 'dog', 'dog','dog'], ["Something", 2013, "blue", "blue"], ["Else", 2014, "yellow", "black"], ["Here", 2015, "white", "gray"]];
}
var
container = document.getElementById('example1'),
hot;
hot = new Handsontable(container, {
data: getCarData(),
colHeaders: ['Car', 'Year', 'Chassis color', 'Bumper color'],
cells: function (row, col, prop) {
var cellProperties = {};
if (row === 0) {
cellProperties.type = 'dropdown';
cellProperties.source = ['yellow', 'dog', 'cat'];
}
return cellProperties;
}
});
Hello stackoverflow community,
is it somehow possible to disable the sorting mechanism in a grid for every column on a condition? Like...
if the grid hasn't any data loaded,
the sorting should be disabled,
else enabled.
I have the problem that if there is no data and you click on a column to sort, the remote sorting mechanism, will start loading the whole data and sorts it, too ...
This behaviour isn't needed or wished, so I want to disable the sorting possibility.
Your help is appreciated.
Thanks in advance and have a nice day.
This is a bit of a hack, but seems to work OK:
http://jsfiddle.net/q43HC/6/
var data = [{
data1: 'test',
data2: 'test'
}, {
data1: 'test2',
data2: 'test2'
}];
var store = Ext.create('Ext.data.Store', {
fields: ['data1', 'data2'],
data: data
});
Ext.define('SampleGrid', {
extend: 'Ext.grid.Panel',
store: store,
height: 250,
width: 400,
title: 'My Window',
columns: [{
text: 'test',
dataIndex: 'data1'
}, {
text: 'test2',
dataIndex: 'data2'
}],
bbar: [{
text: 'Clear Store',
handler: function() {
store.removeAll();
var grid = this.up('grid'),
cols = grid.query('gridcolumn'),
i = 0,
len = cols.length;
for (; i < len; i++) {
cols[i].doSort(null);
cols[i].__toggleSortState = cols[i].toggleSortState;
cols[i].toggleSortState = function() {};
}
}
}, {
text: 'Reload Store',
handler: function() {
store.loadData(data);
var grid = this.up('grid'),
cols = grid.query('gridcolumn'),
i = 0,
len = cols.length;
for (; i < len; i++) {
if (cols[i].__toggleSortState) {
cols[i].toggleSortState = cols[i].__toggleSortState;
}
}
}
}],
renderTo: Ext.getBody()
});
Ext.onReady(function() {
var grd = new SampleGrid();
});
I am just changing the sort state when the data is removed in order to remove any current sorting then replacing the toggleSortState function with an empty one so clicking the header will not sort the column. When reloading the store I put the function back.. You will have to adapt this to your project, but could create a store aware grid with similar logic.
You can do this globally by overriding the Ext.data.Store.sort method. The system I was working on uses remoteSort and hence hits the server everytime the user clicks the column header to sort, even if the grid itself is empty, pretty much same with your problem.
This is the code that you only need to declare in a single location (ie. your ext-overrides file or commons file), instead of in every single grid:
Ext.define('Ext.overrides.data.Store', {
override: 'Ext.data.Store',
sort: function() {
//prevents the grid from submitting a request if store is empty, for remote sort
if (this.count() > 0) {
this.callParent(arguments);
}
}
});
I have written the following function to achieve the same solution:
function disableColumnSorting(disable){
var grid = Ext.getCmp('billRecordGrid'),
cols = grid.query('gridcolumn'),
colLength = cols.length,
i = 0;
for(i; i < colLength; i++) {
if (disable) {
cols[i].sortable= false;
} else {
cols[i].sortable= true;
}
}
}
Thanks to drew630, you gave me a helpful hint, so I could solve my problem on my own.
If you do not want anything to happen when the grid is empty, you could put this in the store of the grid:
listeners: {
beforeload: function() {
return false when my conditions is met.;
}
}
This way your store will not load and nothing will happen. This is also handy when you have a pager component on the grid and where your server expects e.g. extraParams that are not yet set. If you expect extraParams, and when not yet set, the user clicks the refresh on the pager, you end up with exceptions. But with this check, you can prevent a call to the back-end if conditions are not met.
I sometimes set my api.read URL to undefined, (in cases where the store needs extraParams that are not yet set) and only when those params are available, I also set the URL (with a call in the store itself where the url is already set e.g. activateRead(). In the beforeload, I then test if the api.read is undefined or not.
Hope it helps.
Regards
Lawrende
The grid columns may be resizable. I want to store user-adjusted columns width and restore them when the next session starts.
The best way to store columns width I've found is the following:
var element = $('#grid').kendoGrid({
...
resizable: true,
columnResize: function(e) {
var state = {};
this.columns.every(function(c,i) {
state[c.field] = c.width;
return true;
});
var state_txt = JSON.stringify(state);
localStorage['profile_userprofile_grid_column_width'] = state_txt;
}
}
Now I want to restore column width saved in the previous user session. I can read columns width from the storage:
var state = JSON.parse(localStorage['profile_userprofile_grid_column_width']);
Does somebody know some elegant way to apply these values back to the grid if it is already created at this time? The resize handle does it internally, so it is possible, but the code doing it in the grid source is ugly.
You can trigger the columnResize event post initilisation as shown below
function grid_columnResize(e) {
// Put your code in here
console.log(e.column.field, e.newWidth, e.oldWidth);
}
$("#grid").kendoGrid({
columns: [
{ field: "name" },
{ field: "age" }
],
dataSource: [
{ name: "Jane Doe", age: 30 },
{ name: "John Doe", age: 33 }
],
resizable: true
});
var grid = $("#grid").data("kendoGrid");
grid.bind("columnResize", grid_columnResize);
Documentation
This is an old question, but here is what we have. Function handles column widths and groups.
var _updateResultsGridColumns = function(columns, groups) {
var kendoGrid = $resultsGrid.data("kendoGrid");
if (kendoGrid) {
kendoGrid.setOptions({
columns: columns,
});
var dataSource = kendoGrid.dataSource;
dataSource.group(groups);
kendoGrid.setDataSource(dataSource);
}
}