Upgrade to Angular 16 break Sharepoint Ads in : this._history.replaceState is not a function
Asked Answered
G

2

8

I was upgrading my angular apps which run inside the Share Point office adds in. Currently angular app is using version 14, after I upgrade to angular 15 it works fine. But as soon as I upgrade to 16, I get below error.

TypeError: this._history.replaceState is not a function

This happens when calling

 this.router.navigate(['/path_to_component']);

I found a fix on this SO post. Office.js nullifies browser history functions breaking history usage

<script type="text/javascript">
    // Office js deletes window.history.pushState and window.history.replaceState. Cache them and restore them
    window._historyCache = {
        replaceState: window.history.replaceState,
        pushState: window.history.pushState
    };
</script>

<script type="text/javascript" src="https://appsforoffice.microsoft.com/lib/1/hosted/office.js"></script>

<script type="text/javascript">
    // Office js deletes window.history.pushState and window.history.replaceState. Restore them
    window.history.replaceState = window._historyCache.replaceState;
    window.history.pushState = window._historyCache.pushState;
</script>

I am not sure how this is breaking only after upgrade to Angular 16 though its relate to office.js

I am using the same version of office.js.

I have already use hash location strategy. Could any one help me to understand this.

Grigson answered 16/10, 2023 at 21:56 Comment(0)
M
5

Looking at Angular 14/15's source code, we can see that BrowserPlatformLocation contains this method:

override replaceState(state: any, title: string, url: string): void {
    if (supportsState()) {
      this._history.replaceState(state, title, url);
    } else {
      this.location.hash = url;
    }
  }

Sources:

  1. https://github.com/angular/angular/blob/14.0.x/packages/common/src/location/platform_location.ts#L180C3-L186C4 (Angular 14)
  2. https://github.com/angular/angular/blob/15.0.x/packages/common/src/location/platform_location.ts#L180C3-L186C4 (Angular 15)

What you should notice is supportsState():

export function supportsState(): boolean {
  return !!window.history.pushState;
}

In Angular 14/15 there's a fallback case if pushState is not available, so you code works well and also this._history.replaceState() works correctly.

From Angular 16, that check was removed:

override replaceState(state: any, title: string, url: string): void {
    this._history.replaceState(state, title, url);
}

Source: https://github.com/angular/angular/blob/16.0.x/packages/common/src/location/platform_location.ts#L165

So, because office.js removes pushState and replaceState and there's no fallback case, your code breaks (until you use the fix you already found).

Mccowyn answered 19/10, 2023 at 23:14 Comment(4)
I do not know what the "already found" fox is, can you please add a link?Diathermy
I'm sorry, i just noticed that I typed"fox" for some reason, I meant "solution" it wouldn't let me edit it.Diathermy
Hi, if you're referring to my sentence "until you use the fix you already found", i was referring to this link: #42643363Mccowyn
I added an issue to Angular, not sure if it will ever get any attention: github.com/angular/angular/issues/54420Gantz
B
3

The following fix provided for Angular issues worked for me when I upgraded from angular 14 to 17 version in office.js add-in.

https://github.com/angular/angular/issues/54420

  //before bootstrapApplication

  // in office add-ins those are replaced with null and cause router to crash, so we set them to empty functions
  window.history.replaceState ??= (() => {});
  window.history.pushState ??= (() => {});
Ballon answered 24/5 at 22:40 Comment(1)
Might be an obvious answer, but which file is the provided code supposed to be placed in?Syreetasyria

© 2022 - 2024 — McMap. All rights reserved.