Most of my users like to have their list data filtered by Date range (a start date and end date). Some were quite happy with SharePoint List Views in case they have a set of predefined weekly, monthly views. But some users want to filter in custom date range which I wanted to create this using fantastic SPFX reusable controls. Thanks for contributors.
What is used?
- SPFX reusable controls “ListView”
- SPFX reusable controls “DateTimePicker”
- Office UI Fabric react control “Button”
- PNPJS to get user profile details
Step 1: Create SPFX React webpart

Step 2: Install and Import controls
I have used the PnP SPFX reusable react controls Listview. Install it with the below command into the project terminal
npm install @pnp/spfx-controls-react --save --save-exact
I have also used a Button which is from Office UI Fabric React controls, so we need to install the below one. I love using OUIFRC but you can use even a simple button.
npm install office-ui-fabric-react@5.132.0 –save
Now we need to import them into our webpart, so open “.tsx” file and add this import statement just below the default imports
import { ListView, IViewField, SelectionMode} from "@pnp/spfx-controls-react/lib/ListView";
import { DateTimePicker, DateConvention } from '@pnp/spfx-controls-react/lib/dateTimePicker';
import { PrimaryButton } from 'office-ui-fabric-react';
import { SPHttpClient } from '@microsoft/sp-http';
Add the below html tags into the render method inside return section to add ListView, DateTimePicker and Button controls to the webpart
<div className={styles.listview}>
<div className={styles.container}>
<br></br>
<div className={styles.row2}>
<div className={styles.column2}>
<label style={{padding: "30px", verticalAlign: "middle"}}>Start Date : </label>
</div>
<div className={styles.column2}>
<DateTimePicker
dateConvention={DateConvention.Date}
isMonthPickerVisible={false}
showGoToToday={false}
formatDate={this._onFormatDate}
onChange={this._onSelectStartDate}
value={this.state.fromDate}
showLabels={false}
/>
</div>
<div className={styles.column2}>
<label style={{padding: "30px", verticalAlign: "middle"}}>End Date : </label>
</div>
<div className={styles.column2}>
<DateTimePicker
dateConvention={DateConvention.Date}
isMonthPickerVisible={false}
showGoToToday={false}
formatDate={this._onFormatDate}
onChange={this._onSelectEndDate}
value={this.state.toDate}
showLabels={false}
/>
</div>
<div className={styles.column2}>
<PrimaryButton text="Filter" onClick={this._filterClicked} disabled={false} checked={false} />
</div>
</div>
<div>
<br></br>
<h2>Reusable Listview</h2>
<ListView
items={this.state.items}
viewFields={viewFields}
iconFieldName="ServerRelativeUrl"
compact={false}
selectionMode={SelectionMode.multiple}
selection={this._getSelection}
showFilter={true}
filterPlaceHolder="Search..." />
</div>
</div>
</div>
Now you need do decide the columns to display in our ListView webpart, so add these just above the return section
const viewFields: IViewField[] = [
{
name: 'Title',
displayName: 'Title',
sorting: true,
maxWidth: 80
},
{
name: 'Requestor',
displayName: 'Requestor',
sorting: true,
maxWidth: 80
},
{
name: 'RequestDate',
displayName: "Request Date",
sorting: true,
maxWidth: 80
},
{
name: 'Location',
displayName: "Location",
sorting: true,
maxWidth: 80
},
{
name: 'Status',
displayName: "Status",
sorting: true,
maxWidth: 80
}
];
Step 3: Declare and Intialize State
Create an interface to declare the State variables in the .tsx file just below the default import tags
export interface IListviewState {
items: any[];
fromDate?: Date | null;
toDate?: Date | null;
fromDateStr: string;
toDateStr: string;
}
Later initialize them inside using an constructor method inside the class method
constructor(props: IListviewProps, state: IListviewState) {
super(props);
let cdate = new Date();
let dd= (cdate.getFullYear()) +'-'+(cdate.getMonth() + 1) + '-' + cdate.getDate()+'T00:00:00';
this.state = {
items: [],
fromDate: new Date(),
toDate: new Date(),
fromDateStr: dd,
toDateStr: dd,
};
}

Step 4: Add Events
Open the .tsx file and add these functions into the class and just below the render method closes. These functions are required for Date change, Filter Button and to load List data.
private _getSelection(items: any[]) {
console.log('Selected items:', items);
}
private _onFormatDate = (date: Date): string => {
return (date.getMonth() + 1) + '/' + date.getDate() + '/' + (date.getFullYear());
};
//Called on Start Date change and to set State
private _onSelectStartDate = (date1: Date | null | undefined): void => {
//console.log("Date selected"+ (date.getFullYear()) +'-'+(date.getMonth() + 1) + '-' + date.getDate()+'T00:00:00');
var strFromDate: string;
strFromDate= (date1.getFullYear()) +'-'+(date1.getMonth() + 1) + '-' + date1.getDate()+'T00:00:00';
this.setState({ fromDate:date1, fromDateStr: strFromDate}, () => console.log(this.state.fromDate + " "+this.state.fromDateStr));
};
//Called on End Date change and to set State
private _onSelectEndDate = (date2: Date | null | undefined): void => {
var strToDate: string;
strToDate= (date2.getFullYear()) +'-'+(date2.getMonth() + 1) + '-' + date2.getDate()+'T00:00:00';
this.setState({ toDate:date2, toDateStr: strToDate}, () => console.log(this.state.toDate + " "+this.state.toDateStr));
};
//Called when filter button is clicked
public _filterClicked = ()=> {
this._loadList();
}
//To retrieve SP List data
private _loadList():void {
const restApi = `${this.props.context.pageContext.web.absoluteUrl}/_api/web/lists/GetByTitle('Requests')/items?$filter=(RequestDate%20ge%20datetime'${this.state.fromDateStr}' and RequestDate le datetime'${this.state.toDateStr}')`;
this.props.context.spHttpClient.get(restApi, SPHttpClient.configurations.v1)
.then(resp => { return resp.json(); })
.then(items => {
this.setState({
items: items.value ? items.value : []
});
});
}
Add these React methods just below the constructor method. “ComponentDidMount” is called on load and “componentDidUpdate” will be called when there is change in State (when dates are changed and filter is clicked)
public componentDidMount() {
console.log(this.state.fromDate);
//const restApi = `${this.props.context.pageContext.web.absoluteUrl}/_api/web/lists/GetByTitle('Requests')/items?$filter=(RequestDate%20ge%20datetime%272020-01-04T00:00:00%27 and RequestDate%20le%20datetime%272020-01-04T00:00:00%27)`;
this._loadList();
}
public componentDidUpdate(prevProps: IListviewProps, prevState: IListviewState, prevContext: any): void {
if ((this.state.fromDateStr !== prevState.fromDateStr) || (this.state.toDateStr !== prevState.toDateStr)) {
//this._loadList();
}
}

Open “Listview.module.scss” and add the below styles under “listview” tag
.column2 {
float: left;
width: 20%;
}
/* Clear floats after the columns */
.row2 {
content: "";
display: table;
clear: both;
}
Step 6: Add context
Open the “IListviewProps.ts” update them as below
import { WebPartContext } from '@microsoft/sp-webpart-base';
export interface IListviewProps {
context: WebPartContext;
}
Open “ListviewWebPart.ts”, import the pnp/sp
import { sp } from "@pnp/sp";
add this onInit method to set the context
public onInit(): Promise<void> {
return super.onInit().then(_ => {
sp.setup({
spfxContext: this.context
});
});
}

Step 7: Deploy
Finally, we are ready to deploy with our webpart. Let’s package it to move to the site.
gulp build
gulp bundle --ship
gulp package-solution --ship
Get the SPFX package file from “SharePoint\solution” and upload it to your app catalogue site We are ready to add our webpart into a SharePoint page. Create a page in your SharePoint online site, add the webpart into it and publish the page. My webpart loads my list data filtered with only today’s requests.
