/** On Column Click: Event Handler */
// tslint:disable-next-line:no-any
private _onColumnClick = (event: React.MouseEvent<HTMLElement>, column: any) => {
let { sortedItems, columns } = this.state;
const { dateFormat } = this.props;
let isSortedDescending = column.isSortedDescending;
if (column.noSorting) {
event.preventDefault();
} else {
if (sortedItems && columns) {
// If we've sorted this column, flip it.
if (column.isSorted) {
isSortedDescending = !isSortedDescending;
}
// To check if the column data is empty or not
let columnData = sortedItems.filter(item => item[column.fieldName] !== '' &&
item[column.fieldName] !== null && item[column.fieldName] !== undefined);
// To check if the column is having the same data or not
columnData = columnData.filter((item, pos, array) => {return array.
map(mapItem => mapItem[column.fieldName]).indexOf(item[column.fieldName]) === pos; });
// columnData should have more than 1 object in the list to sort and more than 1 unique value to compare
if (columnData.length === 1) {
sortedItems = sortedItems.sort((a, b) => {
// To check the data is not NULL or UNDEFINED(If so, it should come last)
if (a[column.fieldName] === null || a[column.fieldName] === undefined ||
a[column.fieldName] === '') {
return 1;
} else {
return -1;
}
});
} else if (columnData.length > 1 ) {
// Sort the items.
sortedItems = sortedItems.sort((a, b) => {
let firstValue, secondValue;
// To check the data is not NULL or UNDEFINED(If so, it should come last)
if (a[column.fieldName] === null || a[column.fieldName] === undefined ||
a[column.fieldName] === '') {
return 1;
} else if (b[column.fieldName] === null || b[column.fieldName] === undefined ||
b[column.fieldName] === '') {
return -1;
} else {
// To check the data if it is a boolean
if (typeof a[column.fieldName] === 'boolean' && typeof b[column.fieldName] === 'boolean') {
firstValue = a[column.fieldName];
secondValue = b[column.fieldName];
// To check the data is of Number type
} else if (!isNaN(a[column.fieldName]) && !isNaN(a[column.fieldName])) {
firstValue = a[column.fieldName];
secondValue = b[column.fieldName];
// To check the data is of Date type
} else if (moment(a[column.fieldName], dateFormat, true).isValid() &&
moment(b[column.fieldName], dateFormat, true).isValid()) {
firstValue = moment(a[column.fieldName]);
secondValue = moment(b[column.fieldName]);
// The rest is expected to be string
} else {
firstValue = a[column.fieldName].toLowerCase();
secondValue = b[column.fieldName].toLowerCase();
}
}
if (isSortedDescending) {
return firstValue > secondValue ? -1 : 1;
} else {
return firstValue > secondValue ? 1 : -1;
}
});
} else {
event.preventDefault();
}
// Reset the items and columns to match the state.
if (sortedItems.length > 0) {
this.setState({
sortedItems: sortedItems,
isSorted: true,
columns: columns.map(col => {
col.isSorted = (col.key === column.key);
if (col.isSorted) {
col.isSortedDescending = isSortedDescending;
}
return col;
})
});
}
}
}
}
/** DetailsList Usage */
<DetailsList
items={sortedItems}
columns={columns}
layoutMode={layoutMode || DetailsListLayoutMode.justified}
selection={selection}
onRenderItemColumn={onRenderItemColumn || undefined}
setKey="set"
onColumnHeaderClick={this._onColumnClick}
isHeaderVisible={true}
checkboxVisibility={CheckboxVisibility.hidden}
selectionMode={selectionMode || SelectionMode.none}
onActiveItemChanged={onActiveItemChanged ? onActiveItemChanged : undefined}
/>
there is no visible change on the table
The table should update immediately with the sorted list.
On investigating, I could find in DetailsList, newProps and this.props both are updated with the new sorted list. So, in DetailsListBase.prototype.componentWillReceiveProps newProps.items !== items // false thus the rendering is not triggered.
Are you willing to submit a PR to fix? (Yes, No)
Requested priority: (Blocking, High, Normal, Low)
Products/sites affected: (if applicable)
DetailsList will only re-render if a new array of items has been passed in. Array.prototype.sort sorts arrays in-place, so the array being passed to setState and the DetailsList is actually the same one as before.
To get the list to re-render, you can copy the array before sorting: for example,
sortedItems = [...sortedItems].sort(/*...*/). Let me know if this helps.
Specifically because of this LoC if my memory serves me correctly:
Thanks @ecraig12345 . Your suggestion worked. Really appreciate your fast response.
Most helpful comment
DetailsList will only re-render if a new array of items has been passed in.
Array.prototype.sortsorts arrays in-place, so the array being passed to setState and the DetailsList is actually the same one as before.To get the list to re-render, you can copy the array before sorting: for example,
sortedItems = [...sortedItems].sort(/*...*/). Let me know if this helps.