Introduction
Proceeding with the appointments with the PnP React controls today I want to talk about the Progress control.
If you’re interested you can find the code of this sample here.
Visual appearance
First of all let’s start with the visual appearance of the control. In the sample the control pane is used to enable the user changing the behavior of the control.
With all the toggles in the control pane switched off
The control will render as follows
The instance of the control contains four different steps and an error in the final step. This is just to demonstrate the possibilities that the control offers for the various steps.
Configuring the toggle to show the progress in the control
Will display a progress bar in the upper section of the control. This progress bar will increase or decrease when navigating forth and back with the buttons:
When showing the progress bar, is possible to display it as an indeterminate progress with the second toggle:
As you can see, now the progress bar is showing as an infinite progress bar:
The third toggle will hide the actions that are not active or already processed:
In the following GIF you can see how the control behaves now. The actions will be shown progressively:
Now that you have an idea of the visual display of the control, let’s cover how to achieve what you saw via 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 Progress.
To use the control you first need to import it and that can be done as following:
import { IProgressAction, Progress } from "@pnp/spfx-controls-react";
Control instance
Now let’s cover how the control is instantiated. Here you can see the control instance with all the properties used in this sample.
<Progress
title={strings.ProgressTitle}
showOverallProgress={showProgress}
showIndeterminateOverallProgress={showIndeterminateOverallProgress}
hideNotStartedActions={hideNotStartedActions}
actions={actions}
currentActionIndex={this.state.currentActionIndex}
longRunningText={strings.LongRunningText}
longRunningTextDisplayDelay={7000}
/>
An overview of the various properties:
-
title
: the title of the progress control, this will be shown in the upper section of the control. -
showOverallProgress
: this instruct the control if the progress bar have to be shown or not. -
showIndeterminateOverallProgress
: this will set the behavior of the progress bar, if set to true the progress bar will run indefinitely. -
hideNotStartedActions
: if set to true the actions that are not yet processed are hidden from the UI. -
actions
: the set of actions that will be used by the control, those will be covered in a short while. -
currentActionIndex
: the index of the current action. This instruct the control about which action is currently active. -
longRunningText
: this is the text shown when an action is taking longer than the specified delay. -
longRunningTextDisplayDelay
: the delay after which thelongRunningText
will be displayed.
Now let’s cover how the actions are defined. Following there’s the method bound to the control’s actions
property:
private _getActions(): IProgressAction[] {
return [
new InitialAction(),
new PrerequisitesAction(),
new MainAction(),
new FinalAction()
];
}
To dig a little further into how the actions are defined let’s have a look at the BaseAction
class and the classes that extend it.
The BaseAction
class implements the IProgressAction
interface from the PnP React controls package.
import { IProgressAction } from "@pnp/spfx-controls-react/lib/controls/progress/IProgress";
import * as strings from "PnPProgressSampleWebPartStrings";
class BaseAction implements IProgressAction {
title: string;
subActionsTitles?: string[] | undefined;
hasError?: boolean | undefined;
errorMessage?: string | undefined;
}
After the creation of the base class all the actually used actions are created as follows:
export class InitialAction extends BaseAction {
constructor() {
super();
this.title = strings.InitialActionTitle;
}
}
export class PrerequisitesAction extends BaseAction {
constructor() {
super();
this.title = strings.PrerequisitesActionTitle;
}
}
export class MainAction extends BaseAction {
constructor() {
super();
this.title = strings.MainActionTitle;
this.subActionsTitles = [
strings.MainActionStep1,
strings.MainActionStep2,
strings.MainActionStep3,
];
}
}
export class FinalAction extends BaseAction {
constructor() {
super();
this.title = strings.FinalActionTitle;
this.hasError = true;
this.errorMessage = strings.ActionErrorMessage;
}
}
To demonstrate different behaviors there are a couple of different properties set:
-
MainAction
class: within this class thesubActionsTitles
are set. Those are the titles of the sub actions displayed with the main action. -
FinalAction
class: to demonstrate how the errors are handled, thehasError
anderrorMessage
are set.-
hasError
: define if the current action is in an error state. -
errorMessage
: the string that define the error message to be shown to the user.
-
To handle the index of the current action a state property has been created:
export interface IPnPProgressSampleState {
currentActionIndex: number;
}
The index is handled in the state by the two buttons that moves the progress forth and back. Here is the button to handle the forward navigation as sample:
<PrimaryButton
text={strings.Buttons.Next}
onClick={() => {
const newIndex = currentActionIndex + 1 > actions.length ? actions.length : currentActionIndex + 1;
this.setState({ currentActionIndex: newIndex });
}}
disabled={currentActionIndex === (actions.length)}
/>
Conclusions
The Progress
control is convenient as a ready to use control whenever you need to provide a wizard-like user experience. It offers a variety of possibilities and is pretty easy to implement.
If you are interested in knowing more you can check the official documentation here.
Hope this helps!
Top comments (0)