DEV Community

Guido Zambarda
Guido Zambarda

Posted on • Originally published at iamguidozam.blog on

How to create your first SPFx ListView command set extension

Introduction

SharePoint Framework offers various possibilities, one of those is the ability to create an extension that will enable the developer to extend the command bar in a SharePoint list.

To show you what I mean I’ve created a sample solution straight from the default solution that is created with the SharePoint Framework Toolkit. Starting from there I’ve did some changes adding custom icons and some custom text, if you’re interested in viewing the code you can find it here.

Starting with the resulting UI there are a couple of commands in this sample. The “List favorites” one will be shown always:

And when clicking on the command icon a dialog will be opened:

The second command, the “Add to favorites” one, will only be visible when an item is selected:

Also this command will display a dialog when clicked:

Let’s cover a little bit more about how to create the ListView command set and how it’s composed.

Creating a new solution

There are a couple of different fashions to create a ListView command set extension solution and those are:

  • using the SharePoint Framework Toolkit.
  • using the Yeoman generator.

SharePoint Framework Toolkit

The SharePoint Framework Toolkit is an awesome Visual Studio Code extension that helps the developers to create and manage their SPFx solutions. This extension is a great UI tool and allows you to create a new ListView command set extension.

For example the project creation page is the following:

As you can see there is the selectable option to create an extension component and also the type of component to create, which in this case is the ListView Command Set.

Yeoman generator

Using Yeoman is possible to scaffold a SPFx solution using a command line interface. If you’re interested in knowing more you can have a look at one of my previous blog post.

To have an idea of what the tool looks like here is an example of a prompt for creating a new ListView command set solution:

Manifest.json

The ListView command set extension rely on the JSON manifest for defyining the available commands and their representation in the UI.

The manifest file is named in the following fashion [your extension name].manifest.json and you can find it in the same folder of your extension class.

In the sample, my folder structure and manifest name looks like the following:

In the manifest we have, alongside the definition of our extension, the command list items that we will be using. In the sample solution the manifest is something like the following:

{
  "$schema": "https://developer.microsoft.com/json-schemas/spfx/command-set-extension-manifest.schema.json",
  "id": "<guid for your extension>",
  "alias": "BasicListViewCommandSet",
  "componentType": "Extension",
  "extensionType": "ListViewCommandSet",
  "version": "*",
  "manifestVersion": 2,
  "requiresCustomScript": false,
  "items": {
    "ADD_TO_FAVORITES": {
      "title": { "default": "Add to favorites", "it-IT": "Aggiungi ai preferiti", "fr-FR": "Ajouter aux favoris" },
      "iconImageUrl": "<omitted for brevity>",
      "type": "command"
    },
    "LIST_FAVORITES": {
      "title": { "default": "List favorites", "it-IT": "Elenco preferiti", "fr-FR": "Liste des favoris" },
      "iconImageUrl": "<omitted for brevity>",
      "type": "command"
    }
  }
}

Enter fullscreen mode Exit fullscreen mode

As you can see, inside the items property there is a key-value structure for each of the commands used.

Taking the following as example:

"ADD_TO_FAVORITES": {
  "title": { "default": "Add to favorites", "it-IT": "Aggiungi ai preferiti", "fr-FR": "Ajouter aux favoris" },
  "iconImageUrl": "<omitted for brevity>",
  "type": "command"
},
Enter fullscreen mode Exit fullscreen mode

The string value ADD_TO_FAVORITES will be the command name. The command contains an object to represent it in the UI, the properties in details are:

  • title: is an object with strings representing the title of the command. Other than the default string is possible to define localized strings. For each localized string is enough to specify the localization code and the localized string.
  • iconImageUrl: is the URL to the image that will be used as the command icon. The property supports a base64 string representing the image to use. It’s recommended to use an SVG file for the best result possible. The size of the icon will be 16 x 16 pixels.
  • type: will be command for a command object.

Show me the code

When the solution is created a bunch of imports are defined:

import {
  BaseListViewCommandSet,
  type Command,
  type IListViewCommandSetExecuteEventParameters,
  type ListViewStateChangedEventArgs
} from '@microsoft/sp-listview-extensibility';
Enter fullscreen mode Exit fullscreen mode

By default there is a property interface defined, I’ve updated it to stick with my example:

export interface IBasicListViewCommandSetProperties {
  AddToFavoritesText: string;
  ListFavoritesText: string;
}
Enter fullscreen mode Exit fullscreen mode

I’ve defined the commands as constants just to avoid writing the strings everywhere and having a single place where I defined those strings:

const ADD_TO_FAVORITES: string = "ADD_TO_FAVORITES";
const LIST_FAVORITES: string = "LIST_FAVORITES";
Enter fullscreen mode Exit fullscreen mode

The ListView command set class extends the BaseListViewCommandSet which is the base class for the extension:

export default class BasicListViewCommandSet extends BaseListViewCommandSet<IBasicListViewCommandSetProperties> {
Enter fullscreen mode Exit fullscreen mode

The base class offers different methods that can be used, let’s cover those.

onInit

The onInit method is called first and there you can perform the initial setups. In this method is also possible to customize some of the command properties.

Let’s see the code of the sample:

public onInit(): Promise<void> {
  // initial state of the command's visibility
  const addToFavoritesCommand: Command = this.tryGetCommand(ADD_TO_FAVORITES);
  addToFavoritesCommand.visible = false;

  this.context.listView.listViewStateChangedEvent.add(this, this._onListViewStateChanged);

  return Promise.resolve();
}
Enter fullscreen mode Exit fullscreen mode

Here the code is used to retrieve the ADD_TO_FAVORITES command and set it’s default visibility to false since this command will be visible only when selecting a list item.

Other than the command visibility, the onInit method, is also used to register the _onListViewStateChanged used to perform operations when the list view state will change.

onExecute

This method is used when a click is performed on one of the commands.

The argument passed to the method is of type IListViewCommandSetExecuteEventParameters, this interface exposes two properties:

  • itemId: is the identifier of the command.
  • selectedRows: represents an array of the selected rows with the list view fields and the list item values.
public onExecute(event: IListViewCommandSetExecuteEventParameters): void {
  switch (event.itemId) {
    case ADD_TO_FAVORITES:
      Dialog.alert(`${this.properties.AddToFavoritesText}`)
        .catch(() => {
          /* handle error */
        });
      break;
    case LIST_FAVORITES:
      Dialog.alert(`${this.properties.ListFavoritesText}`)
      .catch(() => {
        /* handle error */
      });
      break;
    default:
      throw new Error("Unknown command");
  }
}
Enter fullscreen mode Exit fullscreen mode

In the sample solution the commands do nothing in particular other than showing a dialog with a message. In a real world scenario this is the place where you would insert your business logic.

_onListViewStateChanged

This method, after binding it in the onInit method, will be called when the list view will be updated.

Here you can handle the changes that will be made based on the list view state. One example is the handling of the command visibility.

Remember to call the raiseOnChange method at the end!

private _onListViewStateChanged = (args: ListViewStateChangedEventArgs): void => {
  const addToFavoritesCommand: Command = 
    this.tryGetCommand(ADD_TO_FAVORITES);
  if (addToFavoritesCommand) {
    addToFavoritesCommand.visible =
      this.context.listView.selectedRows?.length === 1;
  }

  // Call the following to update the command bar
  this.raiseOnChange();
}
Enter fullscreen mode Exit fullscreen mode

Test your extension

Is possible to test your extension using gulp. To test the extension it will be enough to execute the following command in the root folder of your solution:

gulp serve
Enter fullscreen mode Exit fullscreen mode

However before doing so it would be better to have a look at the serve.json file. The serve.json file can be found under the config folder placed in the root folder of your solution.

The serve.json file enables to define the URL/s where you want to test your solution. An example of the file from my sample solution is the following:

{
  "$schema": "https://developer.microsoft.com/json-schemas/spfx-build/spfx-serve.schema.json",
  "port": 4321,
  "https": true,
  "serveConfigurations": {
    "default": {
      "pageUrl": "<the URL to your SharePoint site list>",
      "customActions": {
        "<id from the manifest.json>": {
          "location": "ClientSideExtension.ListViewCommandSet.CommandBar",
          "properties": {
            "AddToFavoritesText": "Item added to favorites",
            "ListFavoritesText": "Here should be the list of favorite items."
          }
        }
      }
    },
    "basicListView": {
      "pageUrl": "<the URL to your SharePoint site list>",
      "customActions": {
        "<id from the manifest.json>": {
          "location": "ClientSideExtension.ListViewCommandSet.CommandBar",
          "properties": {
            "AddToFavoritesText": "Item added to favorites",
            "ListFavoritesText": "Here should be the list of favorite items."
          }
        }
      }
    }
  }
}

Enter fullscreen mode Exit fullscreen mode

There are a couple of placeholders that I’ve inserted in the previous code section. Those are just to explain a couple of things, let’s cover those briefly.

Each of the serve configuration objects contains a pageUrl property. The value of the pageUrl property is the address of the page where you want to debug your extension. By default the value set is the following:

"pageUrl": "https://{tenantDomain}/SitePages/myPage.aspx",
Enter fullscreen mode Exit fullscreen mode

You should know that, by default, the {tenantDomain} placeholder is inserted in the pageUrl property value. The placeholder will be replaced while using gulp serve. If you want to know more about this you can have a look at the documentation here.

Once the serve.json is set and the gulp command is executed a page will be opened. In the page that will be opened you will be requested if to load or not the debug scripts. To debug your extension simply click on “Load debug scripts”.

And now you’re ready to debug your new list view command set extension.

Conclusions

Now you have a basic understanding of the list view command set extension. The extension offers an awesome customization of the SharePoint UI in a simple and convenient fashion.

If you want to know more about this extension I suggest you to have a look at the official documentation here.

Hope this helps!

Top comments (0)