Introduction
Proceeding with the appointments with the PnP React controls today I want to talk about the ListView control.
If you’re interested you can find the code of this sample here.
The ListView
control is used to display a view for specific items.
Visual appearance
There are a lot of possibilities with this control, here I want to show some of those functionalities and I will start, as usual, with the visual appearance of the various features.
Starting with the minimal configuration, this is how the control would display:
In the next configuration the columns are manually defined and overrides the automatic generated fields:
If needed, the control has a compact display option which will reduce the space taken by the control:
A great feature is the built-in filtering option. This option will render a text field in the upper section of the component:
This text field will automatically filter the items. The contains filtering operation is performed automatically on every field of the items:
Using the filtering option, is also possible to specify a pre-defined filter for those situation when you want to use a filter specified via code:
An interesting feature is the ability to allow users to drag and drop files onto the component. Here you can see the initial state of the component:
Once a few files gets dropped, a custom function will be called and parse the files to populate the items to be shown in the control:
By default the headers of the component will be scrolled alongside the content, but a specific option enables the headers to be fixed at the top of the control:
Here you can see how the control appears when the content gets scrolled all the way down:
As usual, in those kind of controls, it’s possible to handle the selection of an item and this is also possible with this control:
This will also enable the call of a custom function to handle the selection, but I will cover that in the code section of this post.
As long as the single selection, it’s possible to enable the multi selection:
Another awesome feature is that it’s also possible to group the items by a custom column(s), the resulting UI will be as follows:
Aside from filtering and grouping is also possible define a custom sorting method (aside the default one). In this sample the initial UI rendering is the following:
Once clicked on an header, the custom sorting will be executed. The custom sorting of this example gives the priority to the items with a high priority (red exclamation point) set to true and then apply the default sorting for the selected column:
This works also when the sorting of the column is reversed:
As a final visual example, the ListView
control offers the ability to define a custom rendering for each of the items displayed:
Now that you have a clear understanding of what’s possible, let’s deep dive into the code!
Show me the code
Prerequisites
To use the PnP React controls, first you need to install the package:
npm install @pnp/spfx-controls-react --save --save-exact
After the installation of the package you can proceed with the following instructions to use the ListView component.
To use the control you first need to import it and that can be done as following:
import { ListView } from "@pnp/spfx-controls-react";
in this sample, the full import has a few more items since it is used for different operations. The full import for this sample is the following:
import { GroupOrder, IGrouping, IViewField, ListView, SelectionMode } from "@pnp/spfx-controls-react";
Now that you have a clear understanding about how to install and import the component, let’s cover how to use it in the different instances.
Minimal instance
This instance shows how it’s possible to have the control defined using only the items to show. The control will take care of creating the columns. This is simply achieved as follows:
<ListView items={items}/>
View field instance
The next step is the ability to define which are the fields that will be shown in the control. The fields are defined with a custom function which returns an array of IViewField
:
private _getViewFields(): IViewField[] {
return [
{
name: 'title',
displayName: strings.Fields.Title,
maxWidth: 150,
minWidth: 100,
sorting: true
},
{
name: 'createdBy',
displayName: strings.Fields.CreatedBy,
maxWidth: 100,
minWidth: 100,
sorting: true
},
{
name: 'version',
displayName: strings.Fields.Version,
maxWidth: 100,
minWidth: 80,
sorting: true
},
{
name: 'created',
displayName: strings.Fields.CreatedDate,
maxWidth: 100,
minWidth: 100,
sorting: true,
render: (item: any) => {
if (!item || !item.created) {
return <span>{strings.Fields.NoDate}</span>;
}
return <span>{item.created}</span>;
}
}
];
}
The previous method will be used also in other instances and is bound to the ListView
control using the viewFields
property:
<ListView
items={items}
viewFields={this._getViewFields()}
/>
Compact instance
The compact view can be used as simple as setting the compact
property to true
:
<ListView
items={items}
compact={true}
/>
Show Filter instance
In this instance there are a couple of properties set in order to use the filter. The first property, which enables the control to show the text box, is the showFilter
which accept a boolean value (true
to use the filtering).
The second property, the filterPlaceHolder
one, is used to specify a string to be shown in the text field.
<ListView
items={items}
showFilter={true}
filterPlaceHolder={strings.FilterPlaceHolder}
viewFields={this._getViewFields()}
/>
Default Filter instance
This instance shows how to specify a default filtering using the defaultFilter
property. Here you can just specify a text which will be used to filter the available items.
<ListView
items={items}
defaultFilter='joan'
viewFields={this._getViewFields()}
showFilter={true}
/>
Drag and Drop Files instance
To enable the drag and drop feature, it’s enough to set a couple parameters:
-
dragDropFiles
: which accepts a boolean value, setting it totrue
will enable the feature. -
onDrop
: accept the method that will be used to handle the drag and drop operation.
<ListView
items={droppedItems}
dragDropFiles={true}
onDrop={this._getDropFiles}
/>
As a sample, this is the function used when files are dropped:
private _getDropFiles = (files: any[]): void => {
const droppedItems = [...this.state.droppedItems];
for (let i = 0; i < files.length; i++) {
droppedItems.push({ title: files[i].name });
}
this.setState({
droppedItems: droppedItems
});
}
Sticky Header instance
Enabling the headers to be sticked at the top of the component is easy as setting the stickyHeader
property to true
:
<ListView
items={this._getMoreItems()}
stickyHeader={true}
/>
Handle Selection instance
This instance is used to show how to handle the selection of an item.
The selection of items is enabled with two properties:
-
selection
: accepts the method called when an item is selected. -
selectionMode
: define which type of selection is allowed which, in this case, is the single mode one.
<ListView
items={items}
selection={this._getSelection}
selectionMode={SelectionMode.single}
/>
Just for reference, the sample function just write to the console log the selected item. This will be used also for the multiple selection instance.
private _getSelection(items: any[]): void {
console.log('Selected items:', items);
}
Multiple Selection Mode instance
The only difference from the previous instance is the different value for the selectionMode
property. Here the SelectionMode
used is the multiple
one.
<ListView
items={items}
selection={this._getSelection}
selectionMode={SelectionMode.multiple}
/>
Group By Fields instance
To enable the grouping you can use the groupByFields
property.
<ListView
items={items}
groupByFields={groupByFields}
/>
The property accepts an array which contains the columns used for the grouping and also the sorting order.
const groupByFields: IGrouping[] = [
{
name: "createdBy",
order: GroupOrder.ascending
}
];
Custom Sorting instance
This instance is used to show how to use the custom sorting. To specify a custom sorting function simply a method to the sortItems
property:
<ListView
items={items}
viewFields={this._getAdditionalViewFields()}
sortItems={this._sortItems}
/>
In brief, the function accepts the items to be sorted, the column name and the sorting direction. The code here sorts the items first by the highPriority
field- and then by the column name parameter:
private _sortItems = (items: SampleItem[], columnName: string, descending: boolean): any[] => {
return items.slice().sort((a, b) => {
if (a.highPriority && !b.highPriority) {
return -1;
}
if (!a.highPriority && b.highPriority) {
return 1;
}
const aValue = (a as any)[columnName];
const bValue = (b as any)[columnName];
if (aValue < bValue) {
return descending ? 1 : -1;
}
if (aValue > bValue) {
return descending ? -1 : 1;
}
return 0;
});
}
Custom Render Row instance
At last, here is the instance that uses a custom template for each row. The template is set to the onRenderRow
property. Here you can specify how the rows will be displayed.
<ListView
items={items}
viewFields={[]}
onRenderRow={(props) => {
return (
<div className={`${styles.tableRow} ${props.item.highPriority ? styles.highPriority : ''}`}>
<div className={styles.smallTableCell}>{props.item.highPriority ? '!' : ''}</div>
<div className={styles.tableCell}>{props.item.createdBy}</div>
<div className={styles.tableCell}>{props.item.title}</div>
<div className={styles.tableCell}>{props.item.version}</div>
</div>
);
}}
/>
Conclusions
In my opinion, the ListView control is a practical and reliable tool for handling many common user interface needs. It handles a lot of routine tasks with its built-in features, which can save time and effort during development. At the same time, it offers plenty of customization options, so you can adjust its appearance and behavior to suit specific requirements. Whether you’re working on something simple or more complex, ListView
is straightforward to use and flexible enough to fit a variety of use cases.
If you’re interested in knowing more you can check the official documentation here.
Hope this helps!
Top comments (0)