SPFx associate listview command set to a content type

22 Dec

At the time of writing there is no support to associate a listview command set to a content type using the elements.xml.

In previous versions of SharePoint this could be accomplished using RegistrationType=”ContentType” in combination with for example RegistrationId=”0x01″. In SPFx this leads to an error during the installation of the application. The exception thrown is quite clear, the RegistrationType is not supported.

“…Microsoft.SharePoint.SPException: The specified RegistrationType value is not supported for client-side custom actions. at Microsoft.SharePoint.SPCustomActionElement.UpdateCustomActionsTable…”

An example of an elements.xml file used by the SharePoint Framework looks like:

 
<version="1.0" encoding="utf-8">
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
 <CustomAction 
  Title="ShowAtContentType" 
  RegistrationId="100" 
  RegistrationType="List" 
  Location="ClientSideExtension.ListViewCommandSet.CommandBar" 
  ClientSideComponentId="d61116f8-011e-4e71-9f9d-d06c9ae024cf" 
  ClientSideComponentProperties="{}">
 </CustomAction>
</Elements>

Which associates the custom action with a generic list.

Fortunately there is another possibility to create the association other than using the elements.xml file.

Apply a command set to a list where an item of a specific content type is selected

What to accomplish?

The only situation when the listview command set has to show is when an item of content type ‘ITIdeaDev Item’ is selected in a list.

How to associate the listview command set to this content type?

To prepare for the solution a custom content type ‘ITIdeaDev Item’ is created with Id 0x01000575B0D2D2390447AFB5D4E17C260BE0.
A standard list is created with the standard Item content type and the newly created content type added.

Creating a listview command set using the generator results in example code to show a command set when exactly one item is selected:

@override
 public onListViewUpdated(event: IListViewCommandSetListViewUpdatedParameters): void {
  const compareOneCommand: Command = this.tryGetCommand('COMMAND_1');
  if (compareOneCommand) {
    compareOneCommand.visible = event.selectedRows.length === 1;
  }
 }

The currently selected ListView rows at the time when the event occurred are represented by the event.selectedRows property. A single ‘row’ is the presentation of a list item and it stores an array of cell values for the associated columns.
Fortunately the column ContentType as well as ContentTypeId are part of this array as shown in Figure 1.

Figure 1 – Array of cell values

So it’s quite easy to check if the selected item is of the custom content type:

@override
 public onListViewUpdated(event: IListViewCommandSetListViewUpdatedParameters): void {
  const compareOneCommand: Command = this.tryGetCommand('COMMAND_1');
   if (compareOneCommand) {
    if (event.selectedRows.length === 1) {
     compareOneCommand.visible = false;
     if(event.selectedRows[0].getValueByName("ContentTypeId").startsWith(ctId)){
      compareOneCommand.visible = true;
     }
    }
   }
  }

The figures below show the result: the command set is only shown when the item of the specific content type is selected.

Figure 2 – Command set is shown when item of specific content type is selected


Figure 3 – Command set isn’t visible when an item based on another content type is selected

Apply a command set to a list that has a specific content type available

I can think of another situation: apply a command set to a list that has a specific content type available. This can be useful if the command set updates, removes or adds content of a specific content type.

To accomplish this pnp js is used to question the list about available content types. The result of this is stored in a Promise in an early stage, the onInit method, which can be used in the onListViewUpdated method to determine if the command set has to be visible.

 public existsContentType(ctId: string): Promise<any> {
  return pnp.sp.web.getList(this.context.pageContext.list.serverRelativeUrl).contentTypes.get().then(result => {
   for (var i = 0; i < result.length; i++) {
    if (result[i].StringId.startsWith(ctId)) {
     return true;
    }
   }
  return false;
 });
}

@override
public onInit(): Promis<void> {
 return this.ctPromise = this.existsContentType(ctId);
}

@override
public onListViewUpdated(event: IListViewCommandSetListViewUpdatedParameters): void {
 const compareOneCommand: Command = this.tryGetCommand('COMMAND_1');
 if (compareOneCommand) {
   this.ctPromise.then((result: boolean) => {
    compareOneCommand.visible = result;
   });
 }
}

It doesn’t matter when zero, one or more items are selected, the command set is available as long as the content type is available at the list.

Figure 4 – Command set is visible when more than one item is selected


Figure 5 – Command set is visible when nothing is selected

Summary

The SharePoint Framework has lot of possibilities, even if some things aren’t implemented yet or don’t work as you’re used to or expect. Think outside of your experience and think in the new framework possibilities!

3 Replies to “SPFx associate listview command set to a content type

  1. Hi,
    Nice post.

    But what if you have a List WebPart showing your list among other webparts and you want your extension to show up only on your list and only for a given content type?

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.