Skip to content

Commit

Permalink
Run scroll command via Angular afterRender hook
Browse files Browse the repository at this point in the history
  • Loading branch information
richard-to committed Jan 16, 2025
1 parent 6f644d5 commit eb0abc2
Showing 1 changed file with 39 additions and 27 deletions.
66 changes: 39 additions & 27 deletions mesop/web/src/shell/shell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
HostListener,
NgZone,
Renderer2,
afterRender,
} from '@angular/core';
import {Router, RouterOutlet, Routes, provideRouter} from '@angular/router';
import {MatProgressBarModule} from '@angular/material/progress-bar';
Expand Down Expand Up @@ -62,6 +63,8 @@ export class Shell {
rootComponent!: ComponentProto;
private resizeSubject = new Subject<void>();

private commandScrollKey = '';

constructor(
private zone: NgZone,
private renderer: Renderer2,
Expand All @@ -81,6 +84,10 @@ export class Shell {
this.resizeSubject
.pipe(debounceTime(500))
.subscribe(() => this.onResizeDebounced());

afterRender(() => {
this.maybeExecuteScrollCommand();
});
}

ngOnInit() {
Expand Down Expand Up @@ -116,33 +123,10 @@ export class Shell {
this.channel.resetOverridedTitle();
}
} else if (command.hasScrollIntoView()) {
// Scroll into view
const key = command.getScrollIntoView()!.getKey();
// Schedule scroll into view to run after the current event loop tick
// so that the component has time to render.
setTimeout(() => {
const targetElements = document.querySelectorAll(
`[data-key="${key}"]`,
);
if (!targetElements.length) {
console.error(
`Could not scroll to component with key ${key} because no component found`,
);
return;
}
if (targetElements.length > 1) {
console.warn(
'Found multiple components',
targetElements,
'to potentially scroll to for key',
key,
'. This is probably a bug and you should use a unique key identifier.',
);
}
targetElements[0].parentElement!.scrollIntoView({
behavior: 'smooth',
});
}, 0);
// Store the scroll key so we can defer execution of scroll command until
// after everything is fully rendered. This helps avoid race conditions
// with the scroll behavior.
this.commandScrollKey = command.getScrollIntoView()!.getKey() || '';
} else if (command.hasSetPageTitle()) {
this.channel.setOverridedTitle(
command.getSetPageTitle()!.getTitle() || '',
Expand Down Expand Up @@ -257,6 +241,34 @@ export class Shell {
userEvent.setResize(new ResizeEvent());
this.channel.dispatch(userEvent);
}

// Executes the scroll command if a key has been specified.
maybeExecuteScrollCommand() {
if (this.commandScrollKey) {
const targetElements = document.querySelectorAll(
`[data-key="${this.commandScrollKey}"]`,
);
if (!targetElements.length) {
console.error(
`Could not scroll to component with key ${this.commandScrollKey} because no component found`,
);
return;
}
if (targetElements.length > 1) {
console.warn(
'Found multiple components',
targetElements,
'to potentially scroll to for key',
this.commandScrollKey,
'. This is probably a bug and you should use a unique key identifier.',
);
}
targetElements[0].parentElement!.scrollIntoView({
behavior: 'smooth',
});
this.commandScrollKey = '';
}
}
}

const routes: Routes = [{path: '**', component: Shell}];
Expand Down

0 comments on commit eb0abc2

Please sign in to comment.