SharePoint modern page tutorial: an SPFX Tour sample WebPart

Update: I was mentioned during SharePoint Dev Weekly - Episode 61 – 26th of November 2019
If you want you can see the registration here :)

Hi guys!
Today we’ll talk about a new SPFx sample webpart I made using SharePoint Framework

General needs

Usually, SharePoint sites are user-friendly, especially modern ones. Sometimes though, especially in the context of adoption a new site, like a new Modern Intranet, it is good to offer users the possibility of having a page guide, a tour, a tutorial, so that they do not feel lost like confused John Travolta

Nice new SharePoint Intranet!
But wait: where are my documents? And my tools?

To improve site adoption, you could create a video guide or well-explained documentation. However, some users do not have the time to read the documentation or to watch the video, they would just like to use the new site! For this type of end-users (most of them) you can create a dynamic tour while learning to use the new Intranet based on SharePoint Online.
There are lots of really cool plugin, using react too. I choose to use ReactTourJS.
Another package I decide to use is @pnp/spfx-property-controls a collection of reusable property pane controls for the SharePoint Framework solutions. In a particular way, I decided to try PropertyFieldCollectionData control

SPFx Tour WebPart in action!

Let’s look at how it works, applied to this really cool site The Landing taken from SharePoint look book sample!

When you start the tour, a modal will be displayed, with a description of the highlighted area, and you can go to the next step or go back, thus navigating inside the page.
The user will see the descriptions and will have the opportunity to preview the advice that the publisher thought for him.

SPFx Tour WebPart configuration

The WebPart property pane allows you to:

  • Choice the WebPart from a list of all WebParts on the current page
  • specify a descriptive text
  • specify the sorting, according to which it will be shown in the tutorial
  • enable or not the step within the tour

Code deep-dive

The solution is pushed in my GitHub repository, but I would like to focus on some snippets.

How to retrieve all SPFx WebPart in the current page

  public async GetAllWebpart(): Promise<any[]> {
    // page file
    const file = sp.web.getFileByServerRelativePath(this.context.pageContext.site.serverRequestPath);

    const page = await ClientSidePage.fromFile(file);

    const wpData: any[] = [];

   page.sections.forEach(section => {
      section.columns.forEach(column => {
        column.controls.forEach(control => {
          var wpName = {}
          var wp = {};
          //FIX: check if webPartData are available, in Text Webpart is undefined
          if (control.data.webPartData != undefined) {
            wpName = `sec[${section.order}] col[${column.order}] - ${control.data.webPartData.title}`;
            wp = { text: wpName, key: control.data.webPartData.instanceId };
            wpData.push(wp);
          } else {
            wpName = `sec[${section.order}] col[${column.order}] - "Webpart"`;
            wp = { text: wpName, key: control.data.id };
          }
          wpData.push(wp);

        });

      });
    });
    return wpData;
  }

How to customize @pnp/spfx-property-controls – PropertyFieldCollectionData with a textarea

 {
                      id: "StepDescription",
                      title: "Step Description",
                      type: CustomCollectionFieldType.custom,
                      onCustomRender: (field, value, onUpdate, item, itemId) => {
                        return (
                          React.createElement("div", null,
                            React.createElement("textarea",
                              {
                                style: { width: "600px", height: "100px" },
                                placeholder:"Step description",
                                key: itemId,
                                value: value,
                                onChange: (event: React.FormEvent<HTMLTextAreaElement>) => {
                                  console.log(event);
                                  onUpdate(field.id, event.currentTarget.value);
                                }
                              })
                          )
                        );
                      }
                    },

To locate the WebPart, ReactTourJS needs a selector. I used data-sp-feature-instance-id data property associated with the WebPart instance id

  public static getTourSteps(settings: any[]): any[] {

    var result: any[] = new Array<any>();

    if (settings != undefined) {
      settings.forEach(ele => {
        if (ele.Enabled) {
          result.push(
            {
              selector: '[data-sp-feature-instance-id=\'' + ele.WebPart + '\']',
              content: ele.StepDescription
            });
        }
      });

    }
    return result;
  }

And it is all from my side 🙂

I hope you enjoy my new code contribution!
Cheers
Federico

14 comments

  • Pingback: SharePoint Dev Weekly - Episode 61 - Microsoft 365 Developer Blog

  • Hi Federico,

    Thanks for sharing the code, it’s great!

    Just a question, have you considered having the code run only once per user and storing whether a user has done the tour or not in local storage, so they don’t have to click through the tour each time? or is there some code that manages this in your repo?

    Thanks,
    Ross

    • Hi Ross!
      Thanks for your comment! 🙂 It could be a nice improvement to manage users run (at least once), but it is not included in this version.
      This sample shows a basic approach to SharePoint adoption with a dynamic and configurable tour.
      Btw, cookie or local storage or list-based approach could be a solution in order to manage Tour execution from a specific user.
      Cheers,
      Federico

  • I’ve installed this on a test site and am having issues getting it working. After dropping the webpart on a page I open the webpart properties and all the panel is greyed out and under the tour steps it has the “Loading Data…” spinner which never ends.

    Any suggestions?

    • Hi David 🙂 thanks for your comment!
      Could you please give me others informations? Which browser did you use for testing ?
      Please consider this is a sample Webpart and it’s no bug free 🙂
      Would you like to DM me on twitter, so we can talk quickly if you need assistance, then we can come back here with solution?

      • I’ve tried in Chrome, Firefox, Edge DEV. I will send you a DM in twitter.

        thanks,

        • Great 🙂
          I’ll be there.
          Cheers,
          Federico

        • Hi Rick,
          just clone my repo from scratch and follow “Minimal Path to Awesome”

          restore dependencies: npm install
          build solution gulp build –ship
          bundle solution: gulp bundle –ship
          package solution: gulp package-solution –ship

          *Verify if there are errors or warnings in these phases*

          locate solution at .\sharepoint\solution\react-tour-pnpjs.sppkg
          upload it to your tenant app catalog
          add react-tour-pnpjs app to your site
          add react-tour-pnpjs webpart to your page to see it in action

          Based on my tests, It works with all browsers, in a new empty page (WebPart list in property pane is empty),and in a page with webparts.
          Could you please test in a new page, with no webparts, or with one simple webpart?
          It could be related with a specific webpart 🙂
          Did you check Console tab into Browser Developer Toolbar (F12)?
          Let me know if you find a specific error!
          Cheers,
          Federico

          • Hi Rick,
            after our quick chat, I verified that there is a bug, I did not manage Text Webpart and I did not consider that Text Webpart object has control.webPartData prop undefined.
            The fix is available on my GitHub, just pull the latest version.
            Thanks for the nice conversation today, as shared in char, this is not a solution ready for the production environment, it is just a sample to show new features, new approaches for the community, btw today we learn that this WebPart has different object props 🙂
            Cheers,
            Federico

  • Hi,
    Nice widget. Tried it works in IE but breaks in ie with errors
    Object doesn’t support property or method ‘find’
    Unable to get property ‘getBoundingClientRect’ of undefined or null reference

    Regards,
    Syed

Leave a Reply

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