Route prefix to support hash location
I have a single page containing multiple rapi doc elements:
<rapi-doc
id="rapidoc-service-x"
update-route="true"
route-prefix="#tab-service-x/"
render-style="read"
... other configs ommitted...
></rapi-doc>
I use hashlocation to show API documentation (activate specific rapidoc element) for a specific service.
The following url is created when specific operation is selected:
http://localhost:8080/#tab-service-x/post-/smth/-smth1-/smth2
And unfortunately this url does not scroll to the specific operation.
I've looked into how the scrollTo method is used:
this.scrollTo(window.location.hash.substring(1));
and it's implementation:
async scrollTo(elementId, expandPath = true, scrollNavItemToView = true) {
... other code ommitted...
const contentEl = this.shadowRoot.getElementById(elementId);
if (contentEl) {
isValidElementId = true;
contentEl.scrollIntoView({ behavior: 'auto', block: 'start' });
} else {
isValidElementId = false;
}
So according to the following code, rapidoc is not able to find the element due to tab-service-x/ in the hash.
As I understand, route-prefix is not intended to be used as hash-location prefix now. But is it possible to support such behavior?
for testing pick the build from dist folder
Wow, that was super fast :) Thanks a lot, I will check that on Monday 👍
Hi @mrin9. I've checked and it looks like the following method also requires a change.
async afterSpecParsedAndValidated(spec) {
....
// On first time Spec load, try to navigate to location hash if provided
const locationHash = window.location.hash?.substring(1);
if (locationHash) {
if (this.renderStyle === 'view') {
this.expandAndGotoOperation(locationHash, true, true);
} else {
this.scrollTo(locationHash);
}
....
I've created a short demo that demonstrates that it looks like some more changes are needed:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta http-equiv="Content-Type" content="text/html"/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/flatly/bootstrap.min.css" integrity="sha384-JJl14kOPjuUj+o0fDTJGBSCDKpu1A4BuCmARIetHUvTVmopvVZITFd4AhRMJIlz7" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/@popperjs/[email protected]/dist/umd/popper.min.js" integrity="sha384-IQsoLXl5PILFhosVNubq5LC7Qb9DXgDA9i+tQ8Zj3iwWAwPtgFTxbJ8NT4GN1R8p" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js" integrity="sha384-cVKIPhGWiC2Al4u+LWgxfKTRIcfu0JTxR+EQDz/bgldoEyl4H0zUF0QKbrJ0EcQF" crossorigin="anonymous"></script>
<script src="https://unpkg.com/[email protected]/dist/rapidoc-min.js" crossorigin="anonymous"></script>
</head>
<body>
<header>
<nav class="navbar navbar-dark bg-dark">
<div class="container-fluid">
<form class="d-flex">
<button
onclick="
document.getElementById('rapidoc-pets').setAttribute('spec-url', 'https://petstore.swagger.io/v2/swagger.json')"
type="button" class="btn btn-primary">Set spec url</button>
</form>
</div>
</nav>
</header>
<main>
<div class="row">
<div class="list-group rounded-0 d-none" id="services-swagger-list" role="tablist">
<a class="list-group-item list-group-item-action active"
id="list-pets"
href="#tab-pets"
data-bs-toggle="list" role="tab">pets</a>
</div>
<div class="tab-content" id="nav-tabContent">
<div class="tab-pane active show"
id="tab-pets"
role="tabpanel">
<rapi-doc
id="rapidoc-pets"
route-prefix="#tab-pets/"
update-route="true"
render-style="read"
allow-authentication="false"
allow-server-selection="false"
show-header="false"
show-info="true"
allow-spec-file-load="false"
allow-spec-url-load="false"
></rapi-doc>
</div>
</div>
</div>
</main>
</body>
</html>
Steps to reproduce:
- Open demo html page.
- Press
Set spec urlbutton. (We have lots of services, so we need to load specs only when requsted for specific service. This is how I emulated such behavior). - Add hashlocation to the url
#tab-pets/post-/user. - Reload the page.
Actual result: Page is opened with first operation selected. Expected result: Create user API definition gets opened.
I've tried changing afterSpecParsedAndValidated method to fix the issue:
const locationHash = window.location.hash?.substring(1);
if (locationHash) {
const regEx = new RegExp(`^${this.routePrefix}`, 'i');
const elementId = window.location.hash.replace(regEx, '');
if (this.renderStyle === 'view') {
this.expandAndGotoOperation(elementId, true, true);
} else {
this.scrollTo(elementId);
}
Although it looks to me like a fix, this does not work for a read render-style. This change works only for focused render-style. With read render style page scrolls to the required place and after that scrolls to the overview section.
thanks for testing it out and proposing a solution, let me check it at my end how best it can be addressed. This is happening due to a race condition created my intersection observer and the code you suggested
Thanks. I've had an idea that this was some kind of race condition, because when I was debugging read render style -- everything worked as expected, without debugging -- it did not work. :D
@Aloren I hope you are doing fine. Sorry for whats happening at Kyiv, Ukraine