Update: I was mentioned during SharePoint Dev Weekly - Episode 61 – 26th of November 2019 If you want you can see the registration here :) Update 2: During December, 19 2020 SharePoint Framework Community Call I made a demo of my contribution, here you can find the registration :)
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
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
[…] SharePoint modern page tutorial: an SPFX Tour sample Webpart | Federico Porceddu (Avanade) […]
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
*works in chrome. breaks in IE
Yep syed, 99% just needs @pnp/polyfill-ie11 package.
Let me check.
Cheers,
Federico
Hi Syed,
I test it with IE 11 (11.1130.17134.0) and it works, without polyfill-ie11 (original version from my Github).
Please consider this is a sample WebPart and it’s no bug-free 🙂
You can try to add IE 11 Polyfill package following those instructions,
https://pnp.github.io/pnpjs/documentation/polyfill/
basically
* run this command npm install –save @pnp/polyfill-ie11
* use this import on TourWebPart.ts –> import “@pnp/polyfill-ie11”;
Let me know 🙂
Cheers
Federico
Hi syed,
thanks for the comment 🙂
Never tested on IE, so yes it couldn’t works.
But, let me check, stand-by please 😉
Cheers,
Federico
Hi Federico,
Thank you for the awesome web part. It is working fine in Chrome, Edge, but not in IE.
I have tried Polyfill as you suggested, but no luck.
* run this command npm install –save @pnp/polyfill-ie11
* use this import on TourWebPart.ts –> import “@pnp/polyfill-ie11”;
I have tested in Window 10 , IE 11 . Any thoughts?
Hi Senthil,
thank you so much, appreciate 🙂
Which version of IE?
I test it with IE 11 (11.1130.17134.0) .
Are there specific errors?
Hi Federico,
I have tried in following IE versions with GitHub version and then adding Polyfill.
IE 11 (11.1184.17134.0)
IE 11 (11.592.18362.0)
Getting following errors in console.
SCRIPT438: Object doesn’t support property or method ‘find’
tour-web-part_b13c8f2be70ff6da239b424f90e8a3aa.js (47,235554)
SCRIPT5007: Unable to get property ‘getBoundingClientRect’ of undefined or null reference
tour-web-part_b13c8f2be70ff6da239b424f90e8a3aa.js (47,240709)
Hi Senthil,
following MS docs, https://support.office.com/en-us/article/which-browsers-work-with-office-for-the-web-ad1303e0-a318-47aa-b409-d3a5eb44e452?ui=en-US&rs=en-US&ad=US
IE 11 supports modern pages in IE11 Document Mode.
Could you please verify it?
Btw, it is a sample demo, and actually it doesn’t support and it is not tested on IE 11.
Hi Federico,
Thank you for the great web part. Is it possible to include content in the header (e.g. Hub navigation) or footer? I would love to be able to highlight these aspects to new users in the tour.
Hi Federico,
I have the same question as @DJ,
Is it possible to include content in the header (e.g. Hub navigation) or footer? I would love to be able to highlight these aspects to new users in the tour.
Ty!
Hi,
Can you please upload the react tour package as i am finding it difficult to package it
thanks
Naren
Hi Federico,
Thanks for sharing the code.
I am getting node modules issue while installing NPM. Could you please share the Node version , NPM version and Gulp version so that issue may be fixed to me.
Hi Federico,
I have fixed node module issue. But getting two errors while configuring web titles showing duplicate and not able to add position.
Could you please help me on it.
Hello Surya,
Could you please show how you resolved the module issue?