Skip to content

Commit 0dc4da0

Browse files
committed
docs: snippet-based examples not showing after clicking away and coming back
Fixes that examples based on snippets (e.g. first example for autocomplete) weren't showing up if the user lands on the page, clicks to another tab and then comes back. The problem was that the timing is different on the second run, because we hit the cached rather than fetching the content. These changes resolve it by switching the component's internal state to signals.
1 parent 0d19121 commit 0dc4da0

File tree

3 files changed

+118
-89
lines changed

3 files changed

+118
-89
lines changed

docs/src/app/shared/doc-viewer/doc-viewer.ts

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import {
3030
ViewContainerRef,
3131
input,
3232
inject,
33+
Type,
3334
} from '@angular/core';
3435
import {Observable, Subscription} from 'rxjs';
3536
import {shareReplay, take, tap} from 'rxjs/operators';
@@ -113,17 +114,17 @@ export class DocViewer implements OnDestroy {
113114
if (file) {
114115
// if the html div has field `file` then it should be in compact view to show the code
115116
// snippet
116-
exampleViewerComponent.view = 'snippet';
117-
exampleViewerComponent.showCompactToggle = true;
118-
exampleViewerComponent.file = file;
117+
exampleViewerComponent.view.set('snippet');
118+
exampleViewerComponent.showCompactToggle.set(true);
119+
exampleViewerComponent.file.set(file);
119120
if (region) {
120121
// `region` should only exist when `file` exists but not vice versa
121122
// It is valid for embedded example snippets to show the whole file (esp short files)
122-
exampleViewerComponent.region = region;
123+
exampleViewerComponent.region.set(region);
123124
}
124125
} else {
125126
// otherwise it is an embedded demo
126-
exampleViewerComponent.view = 'demo';
127+
exampleViewerComponent.view.set('demo');
127128
}
128129
}
129130

@@ -175,7 +176,7 @@ export class DocViewer implements OnDestroy {
175176
}
176177

177178
/** Instantiate a ExampleViewer for each example. */
178-
private _loadComponents(componentName: string, componentClass: any) {
179+
private _loadComponents(componentName: string, componentClass: Type<ExampleViewer | HeaderLink>) {
179180
const exampleElements = this._elementRef.nativeElement.querySelectorAll(`[${componentName}]`);
180181

181182
[...exampleElements].forEach((element: Element) => {
@@ -185,9 +186,14 @@ export class DocViewer implements OnDestroy {
185186
const portalHost = new DomPortalOutlet(element, this._appRef, this._injector);
186187
const examplePortal = new ComponentPortal(componentClass, this._viewContainerRef);
187188
const exampleViewer = portalHost.attach(examplePortal);
188-
const exampleViewerComponent = exampleViewer.instance as ExampleViewer;
189-
if (example !== null) {
190-
DocViewer._initExampleViewer(exampleViewerComponent, example, file, region);
189+
const exampleViewerComponent = exampleViewer.instance;
190+
if (example !== null && componentClass === ExampleViewer) {
191+
DocViewer._initExampleViewer(
192+
exampleViewerComponent as ExampleViewer,
193+
example,
194+
file,
195+
region,
196+
);
191197
}
192198
this._portalHosts.push(portalHost);
193199
});

docs/src/app/shared/example-viewer/example-viewer.html

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1+
@let exampleData = this.exampleData();
2+
@let fileUrl = this.fileUrl();
3+
14
<div class="docs-example-viewer-wrapper">
2-
@if (view === 'snippet') {
5+
@if (view() === 'snippet') {
36
<div class="docs-example-viewer-source-compact">
47
<div class="docs-button-bar">
58
<button mat-icon-button type="button" (click)="copySource(snippet())"
@@ -37,7 +40,7 @@
3740
<mat-icon>link</mat-icon>
3841
</button>
3942

40-
@if (showCompactToggle) {
43+
@if (showCompactToggle()) {
4144
<button mat-icon-button
4245
(click)="toggleCompactView()"
4346
matTooltip="View snippet only"
@@ -52,37 +55,39 @@
5255
}
5356

5457
<button mat-icon-button type="button" (click)="toggleSourceView()"
55-
[matTooltip]="view === 'demo' ? 'View code' : 'Hide code'" aria-label="View source">
58+
[matTooltip]="view() === 'demo' ? 'View code' : 'Hide code'" aria-label="View source">
5659
<mat-icon>code</mat-icon>
5760
</button>
5861

5962
<stackblitz-button [example]="example"></stackblitz-button>
6063
</div>
6164

62-
@if (view === 'full') {
65+
@if (view() === 'full') {
6366
<div class="docs-example-viewer-source">
6467
<mat-tab-group animationDuration="0ms" [(selectedIndex)]="selectedTab" mat-stretch-tabs="false">
65-
@for (tabName of _getExampleTabNames(); track tabName) {
68+
@for (tabName of _exampleTabNames(); track tabName) {
6669
<mat-tab [label]="tabName">
6770
<div class="docs-button-bar">
68-
<button mat-icon-button type="button" (click)="copySource(snippet(), selectedTab)"
71+
<button mat-icon-button type="button" (click)="copySource(snippet(), selectedTab())"
6972
class="docs-example-source-copy docs-example-button" matTooltip="Copy example source"
7073
title="Copy example source" aria-label="Copy example source to clipboard">
7174
<mat-icon>content_copy</mat-icon>
7275
</button>
7376
</div>
74-
<code-snippet [source]="exampleTabs[tabName]"></code-snippet>
77+
<code-snippet [source]="exampleTabs()[tabName]"></code-snippet>
7578
</mat-tab>
7679
}
7780
</mat-tab-group>
7881
</div>
7982
}
8083
}
8184

82-
@if (view !== 'snippet') {
85+
@if (view() !== 'snippet') {
8386
<div class="docs-example-viewer-body">
84-
@if (_exampleComponentType && !example?.includes('harness')) {
85-
<ng-template [ngComponentOutlet]="_exampleComponentType"/>
87+
@let componentType = _exampleComponentType();
88+
89+
@if (componentType && !example?.includes('harness')) {
90+
<ng-template [ngComponentOutlet]="componentType"/>
8691
} @else {
8792
<div>This example contains tests. Open in Stackblitz to run the tests.</div>
8893
}

0 commit comments

Comments
 (0)