Started to add a dedicated search page. Started the refactor to have search service manage all the searching and the pages just render out from the observable.
This commit is contained in:
parent
99424acb48
commit
7263a561d9
11 changed files with 119 additions and 9 deletions
|
@ -1,6 +1,7 @@
|
|||
import { HttpClient } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { of } from 'rxjs';
|
||||
import { Subject } from '@microsoft/signalr';
|
||||
import { distinctUntilChanged, filter, map, Observable, of, ReplaySubject, startWith, switchMap } from 'rxjs';
|
||||
import { environment } from 'src/environments/environment';
|
||||
import { SearchResultGroup } from '../_models/search/search-result-group';
|
||||
import { Series } from '../_models/series';
|
||||
|
@ -12,9 +13,23 @@ export class SearchService {
|
|||
|
||||
baseUrl = environment.apiUrl;
|
||||
|
||||
constructor(private httpClient: HttpClient) { }
|
||||
private searchSubject: ReplaySubject<string> = new ReplaySubject();
|
||||
searchResults$: Observable<SearchResultGroup>;
|
||||
|
||||
constructor(private httpClient: HttpClient) {
|
||||
this.searchResults$ = this.searchSubject.pipe(
|
||||
startWith(''),
|
||||
map(val => val.trim()),
|
||||
filter(term => term !== '' && term !== null && term !== undefined),
|
||||
distinctUntilChanged(),
|
||||
switchMap(term => {
|
||||
return this.httpClient.get<SearchResultGroup>(this.baseUrl + 'search/search?queryString=' + encodeURIComponent(term));
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
search(term: string) {
|
||||
this.searchSubject.next(term);
|
||||
if (term === '') {
|
||||
return of(new SearchResultGroup());
|
||||
}
|
||||
|
|
|
@ -49,6 +49,10 @@ const routes: Routes = [
|
|||
path: 'want-to-read',
|
||||
loadChildren: () => import('../app/want-to-read/want-to-read.module').then(m => m.WantToReadModule)
|
||||
},
|
||||
{
|
||||
path: 'search',
|
||||
loadChildren: () => import('../app/search/search.module').then(m => m.SearchModule)
|
||||
},
|
||||
{
|
||||
path: 'library',
|
||||
runGuardsAndResolvers: 'always',
|
||||
|
|
|
@ -13,6 +13,14 @@
|
|||
</div>
|
||||
<div class="dropdown" *ngIf="hasFocus">
|
||||
<ul class="list-group" role="listbox" id="dropdown">
|
||||
<ng-container *ngIf="seeMoreTemplate !== undefined && hasData && searchTerm.length > 0">
|
||||
<li class="list-group-item section-header"><h5 id="seemore-group">See More</h5></li>
|
||||
<ul class="list-group results">
|
||||
<li class="list-group-item">
|
||||
<ng-container [ngTemplateOutlet]="seeMoreTemplate" [ngTemplateOutletContext]="{ $implicit: searchTerm }"></ng-container>
|
||||
</li>
|
||||
</ul>
|
||||
</ng-container>
|
||||
<ng-container *ngIf="seriesTemplate !== undefined && grouppedData.series.length > 0">
|
||||
<li class="list-group-item section-header"><h5 id="series-group">Series</h5></li>
|
||||
<ul class="list-group results" role="group" aria-describedby="series-group">
|
||||
|
@ -109,7 +117,6 @@
|
|||
<ng-container [ngTemplateOutlet]="noResultsTemplate"></ng-container>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</ng-container>
|
||||
</ul>
|
||||
</div>
|
||||
|
|
|
@ -58,6 +58,7 @@ export class GroupedTypeaheadComponent implements OnInit, OnDestroy {
|
|||
@ContentChild('personTemplate') personTemplate: TemplateRef<any> | undefined;
|
||||
@ContentChild('genreTemplate') genreTemplate!: TemplateRef<any>;
|
||||
@ContentChild('noResultsTemplate') noResultsTemplate!: TemplateRef<any>;
|
||||
@ContentChild('seeMoreTemplate') seeMoreTemplate!: TemplateRef<any>;
|
||||
@ContentChild('libraryTemplate') libraryTemplate!: TemplateRef<any>;
|
||||
@ContentChild('readingListTemplate') readingListTemplate!: TemplateRef<any>;
|
||||
@ContentChild('fileTemplate') fileTemplate!: TemplateRef<any>;
|
||||
|
@ -77,7 +78,7 @@ export class GroupedTypeaheadComponent implements OnInit, OnDestroy {
|
|||
}
|
||||
|
||||
get hasData() {
|
||||
return !(this.noResultsTemplate != undefined && !this.grouppedData.persons.length && !this.grouppedData.collections.length
|
||||
return !(!this.grouppedData.persons.length && !this.grouppedData.collections.length
|
||||
&& !this.grouppedData.series.length && !this.grouppedData.persons.length && !this.grouppedData.tags.length && !this.grouppedData.genres.length && !this.grouppedData.libraries.length
|
||||
&& !this.grouppedData.files.length && !this.grouppedData.chapters.length);
|
||||
}
|
||||
|
|
|
@ -192,7 +192,7 @@ NZ0ZV4zm4/L1dfnYNCrjTFq9G03rmj5D+Y4i0OHuL3GFPJytaM54AAAAAElFTkSuQmCC
|
|||
[minQueryLength]="2"
|
||||
initialValue=""
|
||||
placeholder="Search…"
|
||||
[grouppedData]="searchResults"
|
||||
[grouppedData]="(searchService.searchResults$ | async) || searchResults"
|
||||
(inputChanged)="onChangeSearch($event)"
|
||||
(clearField)="clearSearch()"
|
||||
(focusChanged)="focusUpdate($event)"
|
||||
|
@ -301,6 +301,9 @@ NZ0ZV4zm4/L1dfnYNCrjTFq9G03rmj5D+Y4i0OHuL3GFPJytaM54AAAAAElFTkSuQmCC
|
|||
No results found
|
||||
</ng-template>
|
||||
|
||||
<ng-template #seeMoreTemplate let-query>
|
||||
<a routerLink="/search" [queryParams]="{'query': query}">See more</a>
|
||||
</ng-template>
|
||||
</app-grouped-typeahead>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -16,7 +16,6 @@ import { SearchResult } from '../../_models/search-result';
|
|||
import { SearchResultGroup } from '../../_models/search/search-result-group';
|
||||
import { AccountService } from '../../_services/account.service';
|
||||
import { ImageService } from '../../_services/image.service';
|
||||
import { LibraryService } from '../../_services/library.service';
|
||||
import { NavService } from '../../_services/nav.service';
|
||||
|
||||
@Component({
|
||||
|
@ -53,7 +52,7 @@ export class NavHeaderComponent implements OnInit, OnDestroy {
|
|||
|
||||
constructor(public accountService: AccountService, private router: Router, public navService: NavService,
|
||||
public imageService: ImageService, @Inject(DOCUMENT) private document: Document,
|
||||
private scrollService: ScrollService, private searchService: SearchService, private readonly cdRef: ChangeDetectorRef) {
|
||||
private scrollService: ScrollService, public searchService: SearchService, private readonly cdRef: ChangeDetectorRef) {
|
||||
this.scrollElem = this.document.body;
|
||||
}
|
||||
|
||||
|
@ -110,8 +109,10 @@ export class NavHeaderComponent implements OnInit, OnDestroy {
|
|||
this.searchTerm = val.trim();
|
||||
this.cdRef.markForCheck();
|
||||
|
||||
this.searchService.search(val.trim()).pipe(takeUntil(this.onDestroy)).subscribe(results => {
|
||||
this.searchResults = results;
|
||||
this.searchService.search(val.trim());
|
||||
|
||||
this.searchService.search(val.trim()).pipe(takeUntil(this.onDestroy)).subscribe((results: SearchResultGroup) => {
|
||||
//this.searchResults = results;
|
||||
this.isLoading = false;
|
||||
this.cdRef.markForCheck();
|
||||
}, err => {
|
||||
|
|
19
UI/Web/src/app/search/search.module.ts
Normal file
19
UI/Web/src/app/search/search.module.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { SearchComponent } from './search/search.component';
|
||||
import { SearchRoutingModule } from './search.router.module';
|
||||
import { CardsModule } from '../cards/cards.module';
|
||||
|
||||
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
SearchComponent
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
SearchRoutingModule,
|
||||
CardsModule
|
||||
]
|
||||
})
|
||||
export class SearchModule { }
|
17
UI/Web/src/app/search/search.router.module.ts
Normal file
17
UI/Web/src/app/search/search.router.module.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
import { SearchComponent } from './search/search.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: SearchComponent
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes), ],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class SearchRoutingModule { }
|
15
UI/Web/src/app/search/search/search.component.html
Normal file
15
UI/Web/src/app/search/search/search.component.html
Normal file
|
@ -0,0 +1,15 @@
|
|||
<!-- <app-card-detail-layout
|
||||
[isLoading]="loadingSeries"
|
||||
[items]="series"
|
||||
[pagination]="pagination"
|
||||
[filterSettings]="filterSettings"
|
||||
[trackByIdentity]="trackByIdentity"
|
||||
[filterOpen]="filterOpen"
|
||||
[jumpBarKeys]="jumpKeys"
|
||||
[refresh]="refresh"
|
||||
(applyFilter)="updateFilter($event)"
|
||||
>
|
||||
<ng-template #cardItem let-item let-position="idx">
|
||||
<app-series-card [data]="item" [libraryId]="item.libraryId" [suppressLibraryLink]="false" (reload)="loadPage()"[allowSelection]="false"></app-series-card>
|
||||
</ng-template>
|
||||
</app-card-detail-layout> -->
|
0
UI/Web/src/app/search/search/search.component.scss
Normal file
0
UI/Web/src/app/search/search/search.component.scss
Normal file
28
UI/Web/src/app/search/search/search.component.ts
Normal file
28
UI/Web/src/app/search/search/search.component.ts
Normal file
|
@ -0,0 +1,28 @@
|
|||
import { Component, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { AccountService } from 'src/app/_services/account.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-search',
|
||||
templateUrl: './search.component.html',
|
||||
styleUrls: ['./search.component.scss']
|
||||
})
|
||||
export class SearchComponent implements OnInit {
|
||||
|
||||
originalQueryString: string = '';
|
||||
|
||||
constructor(private route: ActivatedRoute, private router: Router, private accountService: AccountService,) {
|
||||
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
const queryString = this.route.snapshot.queryParamMap.get('query');
|
||||
console.log('query: ', queryString)
|
||||
if (queryString === undefined || queryString === null) {
|
||||
//this.router.navigateByUrl('/libraries');
|
||||
return;
|
||||
}
|
||||
this.originalQueryString = queryString;
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue