mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-11-03 03:16:10 -06:00 
			
		
		
		
	infinite scroll for search results
This commit is contained in:
		@@ -1,9 +1,7 @@
 | 
			
		||||
import { Component, Input, OnInit } from '@angular/core';
 | 
			
		||||
import { DomSanitizer } from '@angular/platform-browser';
 | 
			
		||||
import { PaperlessDocument } from 'src/app/data/paperless-document';
 | 
			
		||||
import { PaperlessTag } from 'src/app/data/paperless-tag';
 | 
			
		||||
import { DocumentService } from 'src/app/services/rest/document.service';
 | 
			
		||||
import { SearchResultHighlightedText } from 'src/app/services/rest/search.service';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-document-card-large',
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
import { Component, Input, OnInit } from '@angular/core';
 | 
			
		||||
import { SearchResultHighlightedText } from 'src/app/services/rest/search.service';
 | 
			
		||||
import { SearchHitHighlight } from 'src/app/data/search-result';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-result-hightlight',
 | 
			
		||||
@@ -11,7 +11,7 @@ export class ResultHightlightComponent implements OnInit {
 | 
			
		||||
  constructor() { }
 | 
			
		||||
 | 
			
		||||
  @Input()
 | 
			
		||||
  highlights: SearchResultHighlightedText[][]
 | 
			
		||||
  highlights: SearchHitHighlight[][]
 | 
			
		||||
 | 
			
		||||
  ngOnInit(): void {
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -3,12 +3,11 @@
 | 
			
		||||
 | 
			
		||||
<p>Search string: <i>{{query}}</i></p>
 | 
			
		||||
 | 
			
		||||
<div [class.result-content-searching]="searching">
 | 
			
		||||
<app-document-card-large *ngFor="let result of results"
 | 
			
		||||
    [document]="result.document"
 | 
			
		||||
    [details]="result.highlights">
 | 
			
		||||
<div [class.result-content-searching]="searching" infiniteScroll (scrolled)="onScroll()">
 | 
			
		||||
    <p>{{resultCount}} result(s)</p>
 | 
			
		||||
    <app-document-card-large *ngFor="let result of results"
 | 
			
		||||
        [document]="result.document"
 | 
			
		||||
        [details]="result.highlights">
 | 
			
		||||
 | 
			
		||||
</app-document-card-large>
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<p *ngIf="results.length == 0" class="mx-auto">No results</p>
 | 
			
		||||
</div>
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
import { Component, OnInit } from '@angular/core';
 | 
			
		||||
import { ActivatedRoute } from '@angular/router';
 | 
			
		||||
import { SearchResult, SearchService } from 'src/app/services/rest/search.service';
 | 
			
		||||
import { SearchHit } from 'src/app/data/search-result';
 | 
			
		||||
import { SearchService } from 'src/app/services/rest/search.service';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-search',
 | 
			
		||||
@@ -9,24 +10,50 @@ import { SearchResult, SearchService } from 'src/app/services/rest/search.servic
 | 
			
		||||
})
 | 
			
		||||
export class SearchComponent implements OnInit {
 | 
			
		||||
  
 | 
			
		||||
  results: SearchResult[] = []
 | 
			
		||||
  results: SearchHit[] = []
 | 
			
		||||
 | 
			
		||||
  query: string = ""
 | 
			
		||||
 | 
			
		||||
  searching = false
 | 
			
		||||
 | 
			
		||||
  currentPage = 1
 | 
			
		||||
 | 
			
		||||
  pageCount = 1
 | 
			
		||||
 | 
			
		||||
  resultCount
 | 
			
		||||
 | 
			
		||||
  constructor(private searchService: SearchService, private route: ActivatedRoute) { }
 | 
			
		||||
 | 
			
		||||
  ngOnInit(): void {
 | 
			
		||||
    this.route.queryParamMap.subscribe(paramMap => {
 | 
			
		||||
      this.query = paramMap.get('query')
 | 
			
		||||
      this.searching = true
 | 
			
		||||
      this.searchService.search(this.query).subscribe(result => {
 | 
			
		||||
        this.results = result
 | 
			
		||||
        this.searching = false
 | 
			
		||||
      })
 | 
			
		||||
      this.currentPage = 1
 | 
			
		||||
      this.loadPage()
 | 
			
		||||
    })
 | 
			
		||||
    
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  loadPage(append: boolean = false) {
 | 
			
		||||
    this.searchService.search(this.query, this.currentPage).subscribe(result => {
 | 
			
		||||
      if (append) {
 | 
			
		||||
        this.results.push(...result.results)
 | 
			
		||||
      } else {
 | 
			
		||||
        this.results = result.results
 | 
			
		||||
      }
 | 
			
		||||
      this.pageCount = result.page_count
 | 
			
		||||
      this.searching = false
 | 
			
		||||
      this.resultCount = result.count
 | 
			
		||||
    })
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  onScroll() {
 | 
			
		||||
    console.log(this.currentPage)
 | 
			
		||||
    console.log(this.pageCount)
 | 
			
		||||
    if (this.currentPage < this.pageCount) {
 | 
			
		||||
      this.currentPage += 1
 | 
			
		||||
      this.loadPage(true)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										27
									
								
								src-ui/src/app/data/search-result.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src-ui/src/app/data/search-result.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
			
		||||
import { PaperlessDocument } from './paperless-document'
 | 
			
		||||
 | 
			
		||||
export class SearchHitHighlight {
 | 
			
		||||
  text?: string
 | 
			
		||||
  term?: number
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface SearchHit {
 | 
			
		||||
  id?: number
 | 
			
		||||
  title?: string
 | 
			
		||||
  score?: number
 | 
			
		||||
  rank?: number
 | 
			
		||||
 | 
			
		||||
  highlights?: SearchHitHighlight[][]
 | 
			
		||||
  document?: PaperlessDocument
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface SearchResult {
 | 
			
		||||
 | 
			
		||||
  count?: number
 | 
			
		||||
  page?: number
 | 
			
		||||
  page_count?: number
 | 
			
		||||
 | 
			
		||||
  results?: SearchHit[]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -2,27 +2,9 @@ import { HttpClient, HttpParams } from '@angular/common/http';
 | 
			
		||||
import { Injectable } from '@angular/core';
 | 
			
		||||
import { Observable } from 'rxjs';
 | 
			
		||||
import { PaperlessDocument } from 'src/app/data/paperless-document';
 | 
			
		||||
import { SearchResult } from 'src/app/data/search-result';
 | 
			
		||||
import { environment } from 'src/environments/environment';
 | 
			
		||||
 | 
			
		||||
export class SearchResultHighlightedText {
 | 
			
		||||
  text?: string
 | 
			
		||||
  term?: number
 | 
			
		||||
 | 
			
		||||
  toString(): string {
 | 
			
		||||
    return this.text
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class SearchResult {
 | 
			
		||||
  id?: number
 | 
			
		||||
  title?: string
 | 
			
		||||
  content?: string
 | 
			
		||||
 | 
			
		||||
  score?: number
 | 
			
		||||
  highlights?: SearchResultHighlightedText[][]
 | 
			
		||||
 | 
			
		||||
  document?: PaperlessDocument
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Injectable({
 | 
			
		||||
  providedIn: 'root'
 | 
			
		||||
@@ -31,8 +13,12 @@ export class SearchService {
 | 
			
		||||
  
 | 
			
		||||
  constructor(private http: HttpClient) { }
 | 
			
		||||
 | 
			
		||||
  search(query: string): Observable<SearchResult[]> {
 | 
			
		||||
    return this.http.get<SearchResult[]>(`${environment.apiBaseUrl}search/`, {params: new HttpParams().set('query', query)})
 | 
			
		||||
  search(query: string, page?: number): Observable<SearchResult> {
 | 
			
		||||
    let httpParams = new HttpParams().set('query', query)
 | 
			
		||||
    if (page) {
 | 
			
		||||
      httpParams = httpParams.set('page', page.toString())
 | 
			
		||||
    }
 | 
			
		||||
    return this.http.get<SearchResult>(`${environment.apiBaseUrl}search/`, {params: httpParams})
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  autocomplete(term: string): Observable<string[]> {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user