I have been getting some questions about how to resolve some of the issues with the footer and links in the SharePoint Starter Kit, so I decided to quickly document some of the findings here in a post. That way it is easily accessible to others.
If you haven’t checked out the SharePoint Starter Kit, I suggest you do that. It’s basically a joint effort by representatives from Microsoft, the PnP core team and the community to make a really nice base for a modern intranet solution.
Recently there has been a few issues regarding the portal footer in the SharePoint Starter kit, with the current SharePoint Framework update.
A colleague of mine showed me an issue regarding the footer and IE11 specifically. When I began to investigate the matter I noticed a few other issues in Chrome aswell.
I made a pull request with some fixes and there is both workarounds and some improvements with how the links are being saved.
In the current state you have these issues/things that could be improved:
First off I needed the PnPJs polyfill for IE11 for the footer to even show, you might not need it.
1. In IE11 you cannot open the “edit” dialog for your personal links. It closes right away with an error.
I found that the usage of a Resize Event
was throwing errors in IE11, as Event its not supported. What I did was to replace that code with UIEvents that works in all browsers.
In MyLinksDialog.tsx
componentDidMount
I removed:
window.dispatchEvent(new Event('resize'));
And added:
let resizeEvent = window.document.createEvent('UIEvents');resizeEvent.initUIEvent('resize', true, false, window, 0);window.dispatchEvent(resizeEvent);
So now it looks like this:
public componentDidMount(): void {// fire the resize event to paint the content of the dialoglet resizeEvent = window.document.createEvent('UIEvents');resizeEvent.initUIEvent('resize', true, false, window, 0);window.dispatchEvent(resizeEvent);}
2. Opening the edit dialog and closing it, makes the user unable to open it again. The dialog freezes.
With BaseDialog
and mostly with SPFx 1.7x there is an issue.
We could overwrite the basedialogs onAfterClose
but then it would only work in Chrome. So I ended up unmounting the component right before we close it in the save and cancel methods.
But clicking outside of the dialog does not dismiss
the dialog for some reason, so to fix the error fully I needed to set the dialog to blocking. This just means we cannot click outside, only close it by normal means.
In the constructor of `MyLinksDialog:
super({isBlocking: true});
In the _cancel
and _save
right before the this.close()
of BaseDialog I added:
ReactDOM.unmountComponentAtNode(this.domElement);
3. Opening the dialog and just saving without changes breaks the whole footer.
The method was checking if something had been changed, or else just return an object with null values. Ofcourse then we had no links to map and the footer broke.
So I changed the constructor of MylinksDialog
to take an optional boolean:
constructor(public links: Array<IMyLink>, public isSave?: boolean) {
Then in the _cancel
method I set it to false and in the _save
I set it to true:
this.isSave = false;
this.isSave = true;
Now they look like this with both fixes from 2.
and here:
@autobindprivate _cancel(): void {this.isSave = false;this.links = this.initialLinks;// Fix for all browsers regarding SP Dialog not being to open twiceReactDOM.unmountComponentAtNode(this.domElement);this.close();}@autobindprivate _save(links: Array<IMyLink>): void {this.isSave = true;// Fix for all browsers regarding SP Dialog not being to open twiceReactDOM.unmountComponentAtNode(this.domElement);this.links = links;this.close();}
And in the PortalFooterApplicationCustomizer
check if it’s a save or a cancel:
// Do not save if the dialog was cancelledif (myLinksDialog.isSave) {
And I changed so it always gives you the links nomatter if being saved or not:
result.links = await this.loadLinks();return (result);
So now it looks like this:
@autobindprivate async _editLinks(): Promise<IPortalFooterEditResult> {let result: IPortalFooterEditResult = {editResult: null,links: null,};const myLinksDialog: MyLinksDialog = new MyLinksDialog(this._myLinks);await myLinksDialog.show();// update the local list of linkslet resultingLinks: IMyLink[] = myLinksDialog.links;// Do not save if the dialog was cancelledif (myLinksDialog.isSave) {if (this._myLinks !== resultingLinks) {this._myLinks = resultingLinks;// save the personal links in the UPS, if there are any updateslet upsService: SPUserProfileService = new SPUserProfileService(this.context);result.editResult = await upsService.setUserProfileProperty(this.properties.personalItemsStorageProperty,'String',JSON.stringify(this._myLinks));}}result.links = await this.loadLinks();return (result);}
4. Cancelling still saves links to user profile and the user gets an success message. And the edited values are still there even after cancel.
Since we added the boolean isSave in the last step, now the cancel only returns the values from the user profile. And since we get “fresh” link values it also resets any edits you had done and cancelled.
Before an addition of a link in the dialog, and then a cancel - the value would still be there if you opened the dialog again. Now that is also fixed.
5. The “expand footer” button looks weird in IE11.
This was just some CSS change in PortalFooter.module.scss
changing inheriting to transparent.
.toggleButton {background-color: transparent;border: 0;color: inherit;padding: 0;min-width: 0;div {width: 1em;height: 40px;line-height: 40px;}}
If these small code samples were confusing to you, go into the pull request and have a look. This is one way if fixing some of the issues, and I hope it could be beneficial to some of you.