Added sorting

This commit is contained in:
Fredrik Thorild 2021-09-30 15:01:42 +02:00
parent 39ea25afc2
commit 7a06e35851
10 changed files with 84 additions and 25 deletions

View File

@ -46,6 +46,7 @@ Version|Date|Comments
2.0|January 19, 2020|Upgrade to SPFx 1.10 2.0|January 19, 2020|Upgrade to SPFx 1.10
2.1|June 22, 2020|Added pagination (Abhishek Garg) 2.1|June 22, 2020|Added pagination (Abhishek Garg)
2.2|October 1, 2020 | Added new Pagination Configuration (@beau__cameron) 2.2|October 1, 2020 | Added new Pagination Configuration (@beau__cameron)
2.3|September 30, 2021 | Added sorting (@fthorild)
## Disclaimer ## Disclaimer
**THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.** **THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.**

View File

@ -3,7 +3,7 @@
"solution": { "solution": {
"name": "react-accordion-client-side-solution", "name": "react-accordion-client-side-solution",
"id": "6d6cf05b-cfe5-4d12-af19-19ec3aedcaf9", "id": "6d6cf05b-cfe5-4d12-af19-19ec3aedcaf9",
"version": "2.2.0.0", "version": "2.3.0.0",
"includeClientSideAssets": true, "includeClientSideAssets": true,
"isDomainIsolated": false "isDomainIsolated": false
}, },

View File

@ -1,6 +1,6 @@
{ {
"name": "react-accordion", "name": "react-accordion",
"version": "2.2.0", "version": "2.3.0",
"private": true, "private": true,
"main": "lib/index.js", "main": "lib/index.js",
"engines": { "engines": {

View File

@ -29,10 +29,13 @@
"properties": { "properties": {
"description": "SPFx webpart which shows SharePoint list data in Accordion format", "description": "SPFx webpart which shows SharePoint list data in Accordion format",
"listName": "FAQ", "listName": "FAQ",
"totalItems":20, "totalItems": 20,
"maxItemsPerPage": 5, "maxItemsPerPage": 5,
"allowPaging":true "allowPaging": true,
"customSortField": "",
"sortById": false,
"sortByModified": false
} }
} }
] ]
} }

View File

@ -2,7 +2,7 @@ import * as React from 'react';
import * as ReactDom from 'react-dom'; import * as ReactDom from 'react-dom';
import { Version, DisplayMode } from '@microsoft/sp-core-library'; import { Version, DisplayMode } from '@microsoft/sp-core-library';
import { BaseClientSideWebPart } from "@microsoft/sp-webpart-base"; import { BaseClientSideWebPart } from "@microsoft/sp-webpart-base";
import { IPropertyPaneConfiguration, PropertyPaneSlider, PropertyPaneTextField,PropertyPaneToggle } from "@microsoft/sp-property-pane"; import { IPropertyPaneConfiguration, PropertyPaneSlider, PropertyPaneTextField, PropertyPaneToggle } from "@microsoft/sp-property-pane";
import * as strings from 'ReactAccordionWebPartStrings'; import * as strings from 'ReactAccordionWebPartStrings';
import ReactAccordion from './components/ReactAccordion'; import ReactAccordion from './components/ReactAccordion';
@ -13,16 +13,19 @@ export interface IReactAccordionWebPartProps {
choice: string; choice: string;
title: string; title: string;
displayMode: DisplayMode; displayMode: DisplayMode;
totalItems:number; totalItems: number;
maxItemsPerPage: number; maxItemsPerPage: number;
enablePaging:boolean; enablePaging: boolean;
customSortField: string;
sortById: boolean;
sortByModified: boolean;
updateProperty: (value: string) => void; updateProperty: (value: string) => void;
} }
export default class ReactAccordionWebPart extends BaseClientSideWebPart<IReactAccordionWebPartProps> { export default class ReactAccordionWebPart extends BaseClientSideWebPart<IReactAccordionWebPartProps> {
public render(): void { public render(): void {
const element: React.ReactElement<IReactAccordionProps> = React.createElement( const element: React.ReactElement<IReactAccordionProps> = React.createElement(
ReactAccordion, ReactAccordion,
{ {
@ -31,9 +34,12 @@ export default class ReactAccordionWebPart extends BaseClientSideWebPart<IReactA
siteUrl: this.context.pageContext.web.absoluteUrl, siteUrl: this.context.pageContext.web.absoluteUrl,
title: this.properties.title, title: this.properties.title,
displayMode: this.displayMode, displayMode: this.displayMode,
totalItems:this.properties.totalItems, totalItems: this.properties.totalItems,
maxItemsPerPage: this.properties.maxItemsPerPage, maxItemsPerPage: this.properties.maxItemsPerPage,
enablePaging:this.properties.enablePaging, enablePaging: this.properties.enablePaging,
customSortField: this.properties.customSortField,
sortById: this.properties.sortById,
sortByModified: this.properties.sortByModified,
updateProperty: (value: string) => { updateProperty: (value: string) => {
this.properties.title = value; this.properties.title = value;
} }
@ -53,10 +59,10 @@ export default class ReactAccordionWebPart extends BaseClientSideWebPart<IReactA
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration { protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
//set maxitems to top //set maxitems to top
if(!this.properties.enablePaging){ if (!this.properties.enablePaging) {
this.properties.maxItemsPerPage = this.properties.totalItems; this.properties.maxItemsPerPage = this.properties.totalItems;
} }
return { return {
pages: [ pages: [
{ {
@ -83,7 +89,7 @@ export default class ReactAccordionWebPart extends BaseClientSideWebPart<IReactA
label: strings.EnablePagingLabel label: strings.EnablePagingLabel
}), }),
PropertyPaneSlider('maxItemsPerPage', { PropertyPaneSlider('maxItemsPerPage', {
disabled:!this.properties.enablePaging, disabled: !this.properties.enablePaging,
label: strings.MaxItemsPerPageLabel, label: strings.MaxItemsPerPageLabel,
ariaLabel: strings.MaxItemsPerPageLabel, ariaLabel: strings.MaxItemsPerPageLabel,
min: 3, min: 3,
@ -91,6 +97,14 @@ export default class ReactAccordionWebPart extends BaseClientSideWebPart<IReactA
value: 5, value: 5,
showValue: true, showValue: true,
step: 1 step: 1
}),
PropertyPaneTextField('customSortField', {
label: strings.CustomSortOrder
}),
PropertyPaneToggle('sortById', {
label: strings.SortById
}),PropertyPaneToggle('sortByModified', {
label: strings.SortByModified
}) })
] ]
} }

View File

@ -10,5 +10,8 @@ export interface IReactAccordionProps {
maxItemsPerPage: number; maxItemsPerPage: number;
enablePaging:boolean; enablePaging:boolean;
totalItems:number; totalItems:number;
customSortField:string;
sortById:boolean;
sortByModified:boolean;
updateProperty: (value: string) => void; updateProperty: (value: string) => void;
} }

View File

@ -7,4 +7,5 @@ export interface IReactAccordionState {
listItems: IAccordionListItem[]; listItems: IAccordionListItem[];
isLoading: boolean; isLoading: boolean;
loaderMessage: string; loaderMessage: string;
} error: string;
}

View File

@ -30,7 +30,8 @@ export default class ReactAccordion extends React.Component<IReactAccordionProps
items: [], items: [],
listItems: [], listItems: [],
isLoading: false, isLoading: false,
loaderMessage: '' loaderMessage: '',
error: ''
}; };
if (!this.listNotConfigured(this.props)) { if (!this.listNotConfigured(this.props)) {
@ -73,8 +74,24 @@ export default class ReactAccordion extends React.Component<IReactAccordionProps
} }
private readItems(): void { private readItems(): void {
let restAPI = this.props.siteUrl + `/_api/web/Lists/GetByTitle('${this.props.listName}')/items?$select=Title,Description&$top=${this.props.totalItems}`; const orders = [];
if (this.props.customSortField) {
orders.push(this.props.customSortField);
}
if (this.props.sortById) {
orders.push('ID');
}
if (this.props.sortByModified) {
orders.push('Modified');
}
const selects = `select=Title,Description${this.props.customSortField ? `,${this.props.customSortField}` : ''}`;
const restAPI = this.props.siteUrl + `/_api/web/Lists/GetByTitle('${this.props.listName}')/items?` +
`$${selects}` +
`${orders.length > 0 ? '&$orderby=' + orders.join(',') : ''}` +
`&$top=${this.props.totalItems}`;
this.props.spHttpClient.get(restAPI, SPHttpClient.configurations.v1, { this.props.spHttpClient.get(restAPI, SPHttpClient.configurations.v1, {
headers: { headers: {
@ -86,6 +103,11 @@ export default class ReactAccordion extends React.Component<IReactAccordionProps
return response.json(); return response.json();
}) })
.then((response: { value: IAccordionListItem[] }): void => { .then((response: { value: IAccordionListItem[] }): void => {
if (!response.value) {
this.setState({
error: `No items were found, check the list Title and/or custom sort order field internal name`
});
}
let listItemsCollection = [...response.value]; let listItemsCollection = [...response.value];
@ -95,14 +117,16 @@ export default class ReactAccordion extends React.Component<IReactAccordionProps
items: response.value, items: response.value,
listItems: response.value, listItems: response.value,
isLoading: false, isLoading: false,
loaderMessage: "" loaderMessage: '',
error: ''
}); });
}, (error: any): void => { }, (error: any): void => {
this.setState({ this.setState({
status: 'Loading all items failed with error: ' + error, status: 'Loading all items failed with error: ' + error,
pagedItems: [], pagedItems: [],
isLoading: false, isLoading: false,
loaderMessage: "" loaderMessage: "",
error: `Loading failed. Validate that you have entered a valid List Title and/or internal field name for the custom sort order ${error}`
}); });
}); });
@ -110,6 +134,7 @@ export default class ReactAccordion extends React.Component<IReactAccordionProps
public render(): React.ReactElement<IReactAccordionProps> { public render(): React.ReactElement<IReactAccordionProps> {
let displayLoader; let displayLoader;
let errorMessage;
let faqTitle; let faqTitle;
let { items } = this.state; let { items } = this.state;
let pageCountDivisor: number = this.props.maxItemsPerPage; let pageCountDivisor: number = this.props.maxItemsPerPage;
@ -149,7 +174,7 @@ export default class ReactAccordion extends React.Component<IReactAccordionProps
displayLoader = (null); displayLoader = (null);
} }
if(this.props.enablePaging){ if (this.props.enablePaging) {
if (items.length > 0) { if (items.length > 0) {
pageCount = Math.ceil(items.length / pageCountDivisor); pageCount = Math.ceil(items.length / pageCountDivisor);
} }
@ -157,6 +182,11 @@ export default class ReactAccordion extends React.Component<IReactAccordionProps
pageButtons.push(<PrimaryButton onClick={() => { _pagedButtonClick(i + 1, items); }}> {i + 1} </PrimaryButton>); pageButtons.push(<PrimaryButton onClick={() => { _pagedButtonClick(i + 1, items); }}> {i + 1} </PrimaryButton>);
} }
} }
if (this.state.error) {
errorMessage = <div>{this.state.error}</div>;
}
return ( return (
<div className={styles.reactAccordion}> <div className={styles.reactAccordion}>
<div className={styles.container}> <div className={styles.container}>
@ -175,7 +205,7 @@ export default class ReactAccordion extends React.Component<IReactAccordionProps
<div className={`ms-Grid-row`}> <div className={`ms-Grid-row`}>
<div className='ms-Grid-col ms-u-lg12'> <div className='ms-Grid-col ms-u-lg12'>
{this.state.status} {this.state.status}
<Accordion accordion={false}> <Accordion>
{pagedItems} {pagedItems}
</Accordion> </Accordion>
</div> </div>
@ -186,7 +216,8 @@ export default class ReactAccordion extends React.Component<IReactAccordionProps
</div> </div>
</div> </div>
</div> </div>
{errorMessage}
</div> </div>
); );
} }
} }

View File

@ -5,6 +5,9 @@ define([], function () {
"ListNameLabel": "List Name", "ListNameLabel": "List Name",
"MaxItemsPerPageLabel": "Max number of items per page", "MaxItemsPerPageLabel": "Max number of items per page",
"EnablePagingLabel":"Enable Paging", "EnablePagingLabel":"Enable Paging",
"TotalItemsLabel":"Maximum items to retrieve" "TotalItemsLabel":"Maximum items to retrieve",
"CustomSortOrder":"Custom sort order",
"SortById":"Sort by ID",
"SortByModified":"Sort by modified date"
} }
}); });

View File

@ -5,6 +5,9 @@ declare interface IReactAccordionWebPartStrings {
MaxItemsPerPageLabel: string; MaxItemsPerPageLabel: string;
EnablePagingLabel: string; EnablePagingLabel: string;
TotalItemsLabel:string; TotalItemsLabel:string;
CustomSortOrder:string;
SortById:string;
SortByModified:string;
} }
declare module 'ReactAccordionWebPartStrings' { declare module 'ReactAccordionWebPartStrings' {