Sp-dev-docs: Probable bug inside navigatedEvent listener of SPFx Application Customizer

Created on 5 Jan 2019  路  25Comments  路  Source: SharePoint/sp-dev-docs

Hello guys!

I'm implementing a certain customization via. SPFx extension (i.e., an application customizer) which involves moving of some components (say, quick search box) from OOTB site header area to top placeholder area, as a part of custom header.

I do understand that the OOTB search box component loads asynchronously on the page. This has been taken care of already while performing the component transition. So that part is pretty much achieved quite easily. Now as we know, the OOTB quick search box is not shown on all pages (say, document library, for example), so then in order to comply to OOTB semantics/user experience, it should also not be shown in the custom header as well on such pages. And as I've figured out, there is some MDS kind of partial loading taking place when we navigate across different pages. This means that the full application customizer code is not executed each time and thus the transited component still remains in its place - even though it is not intended any more.

So, of course, some additional logic is needed to hide it again when user navigates to such pages. And in order to also handle the MDS behavior, I started using this.context.application.navigatedEvent.add(this, this._navigatedEventHandler); event handler and build some code to perform cleanup/re-render inside it, so that it triggers each time when user navigates across pages. This seems to do the trick (quite a bit), as it provided me with some kind of listener that can then perform cleanup/re-render when user navigates across different pages.

However, as I've noticed there is some problem with this event handler. It actually fires 2 times instead of 1, for every single page navigation. Apparently, it fires 2 times - one before page navigation starts and one after page navigation is completed (it's just like item adding and item added events). However, there is no way to identify the "navigating" and "navigated" events distinctly. I even tried checking the SPEventArgs parameter which comes as the method argument, but it is always empty. There is no useful information in it.

Any clue if I'm missing out on something here or most likely this is some native issue with SPFx extension, as I understand?

Category

  • [ ] Question
  • [ ] Typo
  • [x] Bug
  • [ ] Additional article idea

Expected or Desired Behavior

I'm expecting either of the following as a behavior:

  • Ideally there should be separate triggers for page navigating or page navigated events, so that appropriate one can be leveraged based on the requirement.
  • Or at least, the SPEventArgs parameter should provide some information about the type of event it is handling (whether it is page navigating or page navigated event).

Observed Behavior

The this.context.application.navigatedEvent() event triggers multiple times (just before page navigation starts and after the page navigation is completed). And on top of it, there is no way to distinguish both these events, because the method parameter/argument (SPEventArgs) is always empty in both cases.

Steps to Reproduce

Just place following code stub inside onInit() method of an application customizer:

this.context.application.navigatedEvent.add(this, (eventArgs: SPEventArgs) => {
    // Issue-1: Custom code to perform cleanup/re-render fires two times...
    this._navigatedEventHandler(eventArgs);

    // Issue-2: The eventArgs parameter is always empty!
    console.log(eventArgs);
});

Quick Workaround to the Issue

I tried a few tweaks in code and was eventually able to distinguish both events with the help of window.location parameter and some additional logic. This way, I got my code working in expected manner even with this 2 times execution of this.context.application.navigatedEvent() event handler. However, I'm not sure, if this is an optimal solution to the given problem definition. Please suggest?

Also it would be really nice, if we can have either both events available separately or at least its exact type (navigating or navigated) is known via. SPEventArgs parameter somehow.

spfx-general fixed-next-drop

Most helpful comment

The code is rolling out, so you should have it soon. The current fix is to not fire multiple events. There isn't currently an -ing/ed pair.

All 25 comments

Thank you for reporting this issue. We will be triaging your incoming issue as soon as possible.

Thanks @devangbhavsar89 . I've got a repro and we're looking into it.

Hi @patmill, do we have any update on this bug-fix?

Also I'm quite eager to know, in what manner will this issue be fixed. Meaning, (a) will we have separate handlers for navigating and navigated events or (b) have information about event type available inside SPEventArgs parameter? I believe, based on the type of fix that will be pushed to customer environments, I'll probably have to make corresponding adjustments to the earlier workaround which I'd made to get it working, to ensure that it continues to work seamlessly once the fix is pushed.

So just wanted to check how is it going to be fixed and when is it expected to roll-out?

The code is rolling out, so you should have it soon. The current fix is to not fire multiple events. There isn't currently an -ing/ed pair.

That's great to know, thanks for the info!

@patmill can you please provide guidance on how to update my existing project so that the fix gets applied? Thank you.

You shouldn't have to do anything - as long as you didn't make temporary workarounds in your code. Are you still seeing issues?

Yes I am. The code inside the this.context.navigatedEvent.add(...) Is firing exactly twice when navigating to a different page.

OK, my bad. Apparently the fix isn't rolling until next week. But once it rolls, you shouldn't need to change anything. Sorry about the incorrect dates.

No worries. Thank you for the information.

Does anyone know if this has been released yet?

@rganser It is active on my Personal Development Tenant which is set with the Targeted release for everyone (Get updates early for your entire organization).

On a Production tenant you would normally have it set to Standard release (Get update when we release them broadly). I haven't tested it in Production, but maybe someone else from Microsoft can confirm that it has been released broadly across all tenants.

I just tested this again in my developer tenant (configured for targeted release) and I'm still seeing the issue. When navigating from one site-page to another the navigatedEvent handler fires exactly twice.

this.context.application.navigatedEvent.add(...)

@patmill the changes shouldn't require any SPFx updates right?

Correct - they should not. Let me follow up with the owning group. Sorry about this.

So, I spent a chunk of time trying to repro this, as did the owner, but we can't seem to see the issue. Can you double check that a) you aren't registering for the event twice and b) you aren't registering the extension twice?

@patmill care to share your code? I'm not registering for the event twice nor am I registering the extension twice. I can re-check in the morning, but am still seeing the event trigger twice.

Here's what I'm using to test @patmill. My console.log() is triggering twice each page change.
Screenshot_37
````
export default class SpoAppInsightsApplicationCustomizer
extends BaseApplicationCustomizer {

@override
public onInit(): Promise {

this.context.application.navigatedEvent.add(this, this.showAlert);

return Promise.resolve<void>();

}

public showAlert(): void {
console.log('navigated change...' + this.context.pageContext.web.serverRelativeUrl + '[' + Date.now() + ']');
}
}
````

OK, my bad. I got it happening again. Looking at the callstack, it appears to actually be worse than navigated getting fired twice. It looks like the entire app customizer is getting reinitialized on a navigate (which is kicking off the initial 'hey, you register for a navigated' event) - at least from my debug query string test. Looking in more.

update OK - noticed one thing, wondering if you can confirm. If I run my customizer w/ just the debug query string (testing it out), I'm getting double events. If I actually install and register it, I only get one event. Is that what you are seeing?

@patmill good catch, it looks like the event duplication occurs while debugging but not once the SPFx extension is deployed and registered on the site.

@patmill I do have a follow-on question though regarding context. Is there a way I can delay the firing until after the navigated page has loaded? At the moment it seems to happen first, so document.location.pathname returns the previous page URL where the link was clicked, rather than the one that has just been navigated to.

OK, good to hear that it is only while debugging. We'll sort that out as well, but it seems less of an emergency. There isn't a way to delay it, but a better way to find out what is rendering is to use the current context. That will be updated.

Agreed, I was just doing some testing and this.context.pageContext.site.serverRequestPath looks to be reliable here. Thanks!

Any update?

Sorry - no update as of yet. Again - this only repro's while using the debug string, not when the customizer is running normally. Is that correct?\ @jayeshvg ?

Sorry - no update as of yet. Again - this only repro's while using the debug string, not when the customizer is running normally. Is that correct?\ @jayeshvg ?

I'm not sure that's true. I use an app-extension to trigger hits to an analytics engine, and had to update my code to try to avoid the duplicate hits just the other day because it wasn't working effectively using the window.location.pathname as noted above. I also had to accommodate for the movement from say a document library to a list library, which uses the /_vti_bin/client.svc/ URL. Moving between 3 libraries will allow the /_vti_bin/client.svc/ to be seen multiple times, causing issues with the logic.

I'm now getting better results after switching to the below, but still occasionally seeing some data come through where the hit is showing data for the previous page. If this weren't an issue in an installed app-extension, I would not expect it to be sending bad data.

When I have some free time maybe I can make a build and throw in some console logs to confirm, but I don't want to interrupt QA.

` // Some pages work like a single page app (SPA), and do not call onInit()
let _sp = this.context.pageContext.legacyPageContext;
let currentUrl = _sp.siteAbsoluteUrl.replace(_sp.siteServerRelativeUrl, "") + _sp.serverRequestPath;

  // Add navigatedEvent callback to reset wt_sp_globals and fire tag where necessary
  this.context.application.navigatedEvent.add(this, function (eventArgs) {

    // https://github.com/SharePoint/sp-dev-docs/issues/1157 - this is often called twice causing issues
    if (!blockNavigated && !blockInit) {
      blockNavigated = true;

      // If old and new url don't match, we've moved using SPA behavior, reset manually.
      let site = this.context.pageContext._site;
      let destinationUrl = site._absoluteUrl.replace(site._serverRelativeUrl, "") + site._serverRequestPath;
      if (currentUrl !== destinationUrl || site._serverRequestPath === "/_vti_bin/client.svc/web/GetList(@listUrl)/RenderListDataAsStream") {
        currentUrl = destinationUrl;
        // Overwrite spPageContextInfo with latest page data
        this.getSpPageContextInfo();
        // Set a boolean for the resetFunctionsModernView in webtrends.sp.js
        window.wt_sp_globals.navigatedEvent = true;
        // Initiate manual reload
        window.wt_sp_globals.wtReloadModernView();
      }

      // Reset navigatedEvent block after a delay
      window.setTimeout(() => {
        blockNavigated = false;
      }, 2500);
    }
  });`

A navigatedEventCompleted or similar callback that triggers when everything is complete and the DOM is ready would really be really helpful to handle this...

This issue is being closed as part of an issue list cleanup project. Issues with no activity in the past 6 months that aren't tracked by engineering as bugs were closed as part of this inititive. If this is still an issue, please follow the steps outlined to re-open the issue.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jonthenerd picture jonthenerd  路  3Comments

christianbueschi picture christianbueschi  路  3Comments

mikeparkie picture mikeparkie  路  3Comments

patrick-rodgers picture patrick-rodgers  路  3Comments

StfBauer picture StfBauer  路  3Comments