DEV Community

Guido Zambarda
Guido Zambarda

Posted on • Originally published at iamguidozam.blog on

Discover the Progress control from the PnP reusable React controls

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
Enter fullscreen mode Exit fullscreen mode

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";
Enter fullscreen mode Exit fullscreen mode

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}
/>
Enter fullscreen mode Exit fullscreen mode

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 the longRunningText 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()
    ];
  }
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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;
  }
}
Enter fullscreen mode Exit fullscreen mode

To demonstrate different behaviors there are a couple of different properties set:

  • MainActionclass: within this class the subActionsTitles are set. Those are the titles of the sub actions displayed with the main action.
  • FinalActionclass: to demonstrate how the errors are handled, the hasError and errorMessage 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;
}
Enter fullscreen mode Exit fullscreen mode

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)}
/>
Enter fullscreen mode Exit fullscreen mode

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)