feat(docs-infra): add useful links if landed on 404 page and no searc… · angular/angular@bf6fbf5 · GitHub
Skip to content

Commit bf6fbf5

Browse files
ajitsinghkaleratscott
authored andcommitted
feat(docs-infra): add useful links if landed on 404 page and no search results found (#34978)
Added additional links which can help user find the things they are looking for when there are no search results (when searching or on a 404 page). Note: This commit increases the main bundle's payload size due to the extra content of the `aio-search-results` component. Fixes #31532 PR Close #34978
1 parent e4f05d1 commit bf6fbf5

5 files changed

Lines changed: 104 additions & 34 deletions

File tree

‎aio/scripts/_payload-limits.json‎

Lines changed: 3 additions & 3 deletions

‎aio/src/app/shared/search-results/search-results.component.html‎

Lines changed: 54 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,57 @@
1-
<div class="search-results">
2-
<div *ngIf="searchAreas.length; then searchResults; else notFound"></div>
1+
<div class="search-results" [ngSwitch]="searchState">
2+
3+
<ng-container *ngSwitchCase="'in-progress'">
4+
<p class="no-results">Searching ...</p>
5+
</ng-container>
6+
7+
<ng-container *ngSwitchCase="'results-found'">
8+
<h2 class="visually-hidden">Search Results</h2>
9+
<div class="search-area" *ngFor="let area of searchAreas">
10+
<h3 class="search-section-header">{{area.name}} ({{area.pages.length + area.priorityPages.length}})</h3>
11+
<ul class="priority-pages" >
12+
<li class="search-page" *ngFor="let page of area.priorityPages">
13+
<a class="search-result-item" href="{{ page.path }}" (click)="onResultSelected(page, $event)">
14+
<span class="symbol {{page.type}}" *ngIf="area.name === 'api'"></span>
15+
<span [class.deprecated-api-item]="page.deprecated">{{ page.title }}</span>
16+
</a>
17+
</li>
18+
</ul>
19+
<ul>
20+
<li class="search-page" *ngFor="let page of area.pages">
21+
<a class="search-result-item" href="{{ page.path }}" (click)="onResultSelected(page, $event)">
22+
<span class="symbol {{page.type}}" *ngIf="area.name === 'api'"></span>
23+
<span [class.deprecated-api-item]="page.deprecated">{{ page.title }}</span>
24+
</a>
25+
</li>
26+
</ul>
27+
</div>
28+
</ng-container>
29+
30+
<ng-container *ngSwitchCase="'no-results-found'">
31+
<div class="search-area">
32+
<p class="no-results">
33+
No results found.<br>
34+
Here are a few links that might be helpful in finding what you are looking for:
35+
</p>
36+
<ul class="priority-pages">
37+
<li class="search-page">
38+
<a class="search-result-item" href="api">API reference</a>
39+
</li>
40+
<li class="search-page">
41+
<a class="search-result-item" href="resources">Resources</a>
42+
</li>
43+
<li class="search-page">
44+
<a class="search-result-item" href="guide/glossary">Glossary</a>
45+
</li>
46+
<li class="search-page">
47+
<a class="search-result-item" href="guide/cheatsheet">Cheat-sheet</a>
48+
</li>
49+
<li class="search-page">
50+
<a class="search-result-item" href="https://blog.angular.io/">Angular blog</a>
51+
</li>
52+
</ul>
53+
</div>
54+
</ng-container>
355
</div>
456

5-
<ng-template #searchResults>
6-
<h2 class="visually-hidden">Search Results</h2>
7-
<div class="search-area" *ngFor="let area of searchAreas">
8-
<h3 class="search-section-header">{{area.name}} ({{area.pages.length + area.priorityPages.length}})</h3>
9-
<ul class="priority-pages" >
10-
<li class="search-page" *ngFor="let page of area.priorityPages">
11-
<a class="search-result-item" href="{{ page.path }}" (click)="onResultSelected(page, $event)">
12-
<span class="symbol {{page.type}}" *ngIf="area.name === 'api'"></span>
13-
<span [class.deprecated-api-item]="page.deprecated">{{ page.title }}</span>
14-
</a>
15-
</li>
16-
</ul>
17-
<ul>
18-
<li class="search-page" *ngFor="let page of area.pages">
19-
<a class="search-result-item" href="{{ page.path }}" (click)="onResultSelected(page, $event)">
20-
<span class="symbol {{page.type}}" *ngIf="area.name === 'api'"></span>
21-
<span [class.deprecated-api-item]="page.deprecated">{{ page.title }}</span>
22-
</a>
23-
</li>
24-
</ul>
25-
</div>
26-
</ng-template>
2757

28-
<ng-template #notFound>
29-
<p class="not-found">{{notFoundMessage}}</p>
30-
</ng-template>

‎aio/src/app/shared/search-results/search-results.component.spec.ts‎

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,12 @@ describe('SearchResultsComponent', () => {
170170
expect(getText()).toContain('Searching ...');
171171
});
172172

173+
it('should not display default links while searching', () => {
174+
fixture.detectChanges();
175+
const resultLinks = fixture.debugElement.queryAll(By.css('.search-page a'));
176+
expect(resultLinks.length).toEqual(0);
177+
});
178+
173179
describe('when a search result anchor is clicked', () => {
174180
let searchResult: SearchResult;
175181
let selected: SearchResult|null;
@@ -214,9 +220,25 @@ describe('SearchResultsComponent', () => {
214220
});
215221

216222
describe('when no query results', () => {
217-
it('should display "not found" message', () => {
223+
beforeEach(() => {
218224
setSearchResults('something', []);
225+
});
226+
227+
it('should display "not found" message', () => {
219228
expect(getText()).toContain('No results');
220229
});
230+
231+
it('should contain reference links', () => {
232+
const resultLinks = fixture.debugElement.queryAll(By.css('.search-page a'));
233+
const resultHrefs = resultLinks.map(a => a.nativeNode.getAttribute('href'));
234+
expect(resultHrefs.length).toEqual(5);
235+
expect(resultHrefs).toEqual([
236+
'api',
237+
'resources',
238+
'guide/glossary',
239+
'guide/cheatsheet',
240+
'https://blog.angular.io/',
241+
]);
242+
});
221243
});
222244
});

‎aio/src/app/shared/search-results/search-results.component.ts‎

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
import { Component, EventEmitter, Input, OnChanges, Output } from '@angular/core';
22
import { SearchResult, SearchResults, SearchArea } from 'app/search/interfaces';
33

4+
enum SearchState {
5+
InProgress = 'in-progress',
6+
ResultsFound = 'results-found',
7+
NoResultsFound = 'no-results-found'
8+
}
9+
410
/**
511
* A component to display search results in groups
612
*/
@@ -23,11 +29,18 @@ export class SearchResultsComponent implements OnChanges {
2329
resultSelected = new EventEmitter<SearchResult>();
2430

2531
readonly defaultArea = 'other';
26-
notFoundMessage = 'Searching ...';
32+
searchState: SearchState = SearchState.InProgress;
2733
readonly topLevelFolders = ['guide', 'tutorial'];
2834
searchAreas: SearchArea[] = [];
2935

3036
ngOnChanges() {
37+
if (this.searchResults === null) {
38+
this.searchState = SearchState.InProgress;
39+
} else if (this.searchResults.results.length) {
40+
this.searchState = SearchState.ResultsFound;
41+
} else {
42+
this.searchState = SearchState.NoResultsFound;
43+
}
3144
this.searchAreas = this.processSearchResults(this.searchResults);
3245
}
3346

@@ -43,7 +56,6 @@ export class SearchResultsComponent implements OnChanges {
4356
if (!search) {
4457
return [];
4558
}
46-
this.notFoundMessage = 'No results found.';
4759
const searchAreaMap: { [key: string]: SearchResult[] } = {};
4860
search.results.forEach(result => {
4961
if (!result.title) { return; } // bad data; should fix

‎aio/src/styles/2-modules/_search-results.scss‎

Lines changed: 10 additions & 1 deletion

0 commit comments

Comments
 (0)