Repository: angular
Issue: Avoid anchorScrolling DOMException error with hash fragments that are not valid selectors
Labels: type: bug/fix,freq3: high,area: router,state: confirmed,P3

<!--
PLEASE HELP US PROCESS GITHUB ISSUES FASTER BY PROVIDING THE FOLLOWING INFORMATION.

ISSUES MISSING IMPORTANT INFORMATION MAY BE CLOSED WITHOUT INVESTIGATION.
-->

## I'm submitting a...
<!-- Check one of the following options with "x" -->
<pre><code>
[ ] Regression (a behavior that used to work and stopped working in a new release)
[ ] Bug report  <!-- Please search GitHub for a similar issue or PR before submitting -->
[ ] Performance issue
[x] Feature request
[ ] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question
[ ] Other... Please describe:
</code></pre>

## Current behavior
<!-- Describe how the issue manifests. -->
If `anchorScrolling` is enabled on the Angular router and the app loads a route that has a hash that does not follow an appropriate format expected for a selector, then a `DOMException` error is thrown.

For example, `#somehash` will not return the error, since this is a valid format for an element selector, even if it is not present on the page (scrolling will fail silently in this case). However, `#somedata=other` will return the error, since this is not a valid element selector and `querySelector` doesn't know what to do with it.

## Expected behavior / Feature request
<!-- Describe what the desired behavior would be. -->
I would expect some way to enable using hash fragments that are not valid DOM selectors without an error, possibly by setting an additional configuration option in `ExtraOptions` for the Router (which can be used in conjunction with `anchorScrolling: 'enabled'`). If the error is still present by default, that is fine as it encourages good practices. However, there is a major use case in which avoiding the error is not currently possible if `anchorScrolling` is enabled (detailed below in motivation). Adding a setting to allow the error to not be thrown might be a good option: possibly something like `allowDataHash`.

Alternatively, if there was a way to _exempt_ an individual route from `anchorScrolling` that was set on the module level, that would also be effective in this scenario.

## Minimal reproduction of the problem with instructions
<!--
For bug reports please provide the *STEPS TO REPRODUCE* and if possible a *MINIMAL DEMO* of the problem via
https://stackblitz.com or similar (you can use this template as a starting point: https://stackblitz.com/fork/angular-gitter).
-->
[GitHub repo with instructions and sample link](https://github.com/kmaida/anchorScrolling-fr)

In any Angular 7 application with routing, enable `anchorScrolling` in the RouterModule's `ExtraOptions`:

```
@NgModule({
  imports: [RouterModule.forRoot(routes, { anchorScrolling: 'enabled'} )],
  exports: [RouterModule]
})
```

Then attempt to access any route with a hash fragment that is not a valid DOM selector. This could be something as simple as:

```
#somehash=data
```

or something more realistic, such as:

```
#access_token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkZha2UgVG9rZW4iLCJpYXQiOjE1MTYyMzkwMjJ9.fg-Dm3WJDDPt3J18KcIipEka0n92sFbIF9N7JqCLnQ_194uScpG7nt9JOEDHE0lqgmNTKf1xr31X5rQPO1HkmGMPzQQ64TLoyr1qs8azzdpJKdm3w4R5qn9Z52zA1deIa1-dBShXrC0ynhXBCXaWaCymRD7n6duyBbuZAmAieaI&expires_in=86400
```

## What is the motivation / use case for changing the behavior?
<!-- Describe the motivation or the concrete use case. -->
There is a **major use case** for data being passed in a hash fragment, and it is done this way _in accordance with IETF standards_:

When conforming to [OIDC implicit grant standards](https://tools.ietf.org/html/rfc6749#section-4.2) for authentication in Single Page Applications, data is returned from any OIDC-conformant authorization server (including but not limited to Auth0, Okta, Gigya, Ping Identity, Cognito, etc.) in a hash fragment. This hash fragment follows a format that resembles the following:

```
#access_token=<jwt token>&expires_in=86400
```

The most common way to handle this in SPAs is to set up a callback route. This is the route that the authorization server redirects back to (`redirect_uri`) and adds the hash data to. In the application, the hash is parsed and then removed and the user is redirected within the SPA.

If no authorization server is being used, throwing the error may normally be fine, as it is likely expected that if a user is passing data in the URL, they should use query parameters with `?` instead of a hash fragment with `#`. 

However, it is currently not possible to avoid this error while using implicit grant with OIDC-conformant authorization servers using redirect mode with `anchorScrolling` enabled. The primary current workaround is to remove `anchorScrolling` and re-implement anchor scrolling functionality _manually_ instead.

## Environment

<pre><code>
Angular version: 7.0.1
<!-- Check whether this is still an issue in the most recent Angular version -->
</code></pre>