Forum Discussion
Debugging SPFx App Customizer
I have had great success debugging SPFx web parts using the Chrome extension. Is there a way to get this to work with the framework extensions? I'm trying to build an Application Customizer that builds a menu in the header based on the contents of a SP links list ('OrangeLinks') and having a heck of time figuring out why I can't get it to work.
The idea is pretty simple: in the onRender() event I am assigning some html to the _headerPlaceholder.domElement.innerHTML, then calling a method to get the links out of the list which in turn calls a method to use the returned data to construct the html for the header. When all the data has been turned into HTML links, I am assigning that to the <div> that has already been put in the _headerPlaceholder. Here's the code:
public onRender(): void { if (!this._headerPlaceholder) { this._headerPlaceholder = this.context.placeholders.tryAttach( 'PageHeader', { onDispose: this._onDispose }); // The extension should not assume that the expected placeholder is available. if (!this._headerPlaceholder) { console.error('The expected placeholder was not found.'); return; } if (this.properties) { let headerString: string = this.properties.Header; if (!headerString) { headerString = '(Header property was not defined.)'; } if (this._headerPlaceholder.domElement) { this._headerPlaceholder.domElement.innerHTML = ` <div class="${styles.app}"> <div class="ms-bgColor-orange ms-fontColor-white ${styles.header}"> <div id="orangeLinks"></div> </div> </div>`; } this.getOrangeLinks(); } } private getOrangeLinks(): void { pnp.sp.web.lists.getByTitle('OrangeLinks').items.select('URL').get().then((links: any) => { this.buildOrangeLinks(links); }); } private buildOrangeLinks(links: any): void { let linkList: string = ``; for (let i: number = 0; i < links.length; i++) { //--- if there are already some links, add spaces before this one if (i > 0) { linkList += ` | `; } let link = `<a href="${escape(links[i].URL.Url)}" target="_blank">${escape(links[i].URL.Description)}</a>`; linkList += link; } $('#orangeLinks').html(linkList); return; }
All I get is blank header.
Funny enough, this scenario (render()->pnp data function->html building function & assignment by jQuery) works just fine in a SPFx web part, so something about the scope or timing of execution must be different. Any thoughts would be most welcome.
Apparently there are some additional instuctions required for the PnP JS and SPFx to play nicely with one another. Thanks to Patrick Rodgers for pointing me to the missing key described in Using sp pnp js in SharePoint Framework - Establish Context.
A single call in the onInit() method override does the trick:
@override public onInit(): Promise<void> { return super.onInit().then(_ => { //--- ensure that the current web is used for all pnp calls pnp.setup({ spfxContext: this.context }); }); }
The REST call is now forming properly. It sure would be nice to have complete, organized documentation all together in ONE PLACE. :)
Thanks again for your interest and assistance.
Hi Joseph Ackerman,
I suspect that
pnp.sp.web.lists.getByTitle('OrangeLinks').items.select('URL').get().then((links: any) => {
... }isn't returning any links.
Can you add console.log("started") at the beginning of the getOrangeLinks method to make sure that the method is called at all.
then can you add a console.log(links) to make sure that we get any results returned?
- Joseph AckermanIron Contributor
Hello Pieter Veenstra, Thanks for the reply.
It does indeed seem that no links are being returned but it turns out not to be what I thought. I added the console log call as you suggested like so:
But when I went to the console tab of the inspector window in my browser, I noticed this:
For some reason it seems that the translation from the PnP call to the REST call is adding the SitePages folder to the path; it's now obvious why the call is not returning any items! If I remove the offending folder from the path and just plug the result into the address bar of the browser, you can see that I am returning the items expected (in the default atom format, but it proves that the list is there and will return rows if the call is properly constructed):
So my question now is: why is the PnP.js not making the correct REST call? Have I missed a step somewhere? Am I making a faulty assumption that pnp.sp.web represents the context of the current default web site? Or is it something else?
Thanks for your input, btw. I've been doing traditional SP Development for 10 years and am still climbing the learning curve on the new "remote" platform.
- Can you try without the select. You should get all items coming back. If mot then your list and is incorrect.