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:
Joseph Milazzo 2022-11-09 09:09:51 -06:00
parent 99424acb48
commit 7263a561d9
11 changed files with 119 additions and 9 deletions

View file

@ -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());
}

View file

@ -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',

View file

@ -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>

View file

@ -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);
}

View file

@ -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>

View file

@ -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 => {

View 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 { }

View 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 { }

View 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> -->

View 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;
}
}