I made two posts at once and here is the previous: Findings from issues with SharePoint Starter Kit
Another post about SharePoint Starter Kit. This time it’s a small post about saving links to the “my links”. As I see it, the starter kit has been created to showcase a lot of best practices and creative ways of doing things. But it’s also quite generic, which is good because it suits so many purposes, but it also means that we might have to adjust it in some cases.
A colleague of mine asked me how we could save more “complex” urls containing querystrings etc. If you remove the validation and try to save whatever URL you will get errors, since the special characters needs to be encoded.
First of there is a regexp to see that only ok simple urls are entered, which is good in some cases. For this scenario we had to remove that validation check.
“My Links” are being saved to you userprofile via a service call, that utilizes XML. And that XML presents a few “challenges” as we need to encode our URL values so they are ok for saving, or else we’re bound to have errors.
So what I basicly did was:
private _encodeValue(value: string): string {return newValue = value.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, ''');}
private _checkHttp(url): string {if (!/^(f|ht)tps?:\/\//i.test(url)) {url = "http://" + url;}return url;}
Here we are using map
which means that we return an array based on the callback function we supply. In this case we encode both the title and the url. In the url case we use the _checkHttp
to check and possible “fix” the http:// situation, before the value is being encoded.
Then we return all the links like they were but encoded.
We are only doing this encoding when we save the links to the user profile, so they will look “normal” in the UI.
private _encodeLinks(links: IMyLink[]) {const result: IMyLink[] = links.map(l => ({ ...l, title: this._encodeValue(l.title), url: this._encodeValue(this._checkHttp(l.url)) }));return result;}
This is how my new _editLinks looks like. It should also be noted that it includes the changes made in the previous blog post.
For this specific purpose I have only changed one row. This is added just before the saving to the user profile.
this._myLinks = this._encodeLinks(this._myLinks);
@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;// Encode the linksthis._myLinks = this._encodeLinks(this._myLinks);// 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);}