Articles in this section
Category / Section

How to Close the Search Box in a Custom Toolbar in Angular PDF Viewer

14 mins read

How to Close the Search Box in a Custom Toolbar in Angular PDF Viewer

Description:

This article demonstrates how to close the search box in a custom toolbar in the Syncfusion PDF Viewer component within an Angular application. After following this guide, users will be able to close the search box programmatically by clicking a “Close” button within the custom toolbar.

Solution:

To close the search box, you can use a custom toolbar and a toggle mechanism to show and hide the search input field. Specifically, in the findText() function, we toggle the visibility of the search box, and in the search results, we allow users to close the search box with a custom close button. This solution ensures that users can easily hide the search box when no longer needed.

Prerequisites:

Before diving into the implementation, ensure that the following steps are completed:

  1. Syncfusion PDF Viewer Setup: Make sure the Syncfusion PDF Viewer is installed and set up in your Angular project. Follow the Getting Started with Syncfusion PDF Viewer for Angular guide if you haven’t already.
  2. Basic Knowledge of Angular: Familiarity with Angular components and the basic setup of Angular projects will help you follow along with the implementation.
Code Snippets
Install and Configure Syncfusion PDF Viewer and Toolbar
app.component.ts

First, make sure to import the necessary modules and services for the Syncfusion PDF Viewer and toolbar:

import {
  Component,
  ViewEncapsulation,
  OnInit,
  ViewChild,
  Inject,
} from '@angular/core';
import {
  PdfViewerComponent,
  LinkAnnotationService,
  BookmarkViewService,
  MagnificationService,
  ToolbarService,
  NavigationService,
  TextSelectionService,
  PrintService,
  DynamicStampItem,
  SignStampItem,
  StandardBusinessStampItem,
  PageChangeEventArgs,
  LoadEventArgs,
  AnnotationService,
  FormDesignerService,
  PageOrganizerService,
  TextSearchService,
  TextSelection,
  PdfViewerModule,
} from '@syncfusion/ej2-angular-pdfviewer';
import {
  ToolbarComponent,
  MenuItemModel,
  ToolbarModule,
  MenuModule,
} from '@syncfusion/ej2-angular-navigations';
import { DialogComponent } from '@syncfusion/ej2-angular-popups';
import { ClickEventArgs } from '@syncfusion/ej2-buttons';
import { SwitchComponent, SwitchModule } from '@syncfusion/ej2-angular-buttons';
Create the PDF Viewer Component
app.component.html

Here is the basic structure for the PDF viewer component in the app.component.html file:

<style>
  .control-section{
      margin-top: 100px;
  }
</style>
<div class="control-section">
  <div class="flex-container">
    <div class="e-message render-mode-info">
    </div>
  </div>
  <div class="content-wrapper e-tbar-section">
    <div class="e-sample-resize-container">
      <ejs-toolbar id="topToolbar" #customToolbar>
        <e-items>
          <e-item
            prefixIcon="e-icons e-search"
            (click)="findText($event)"
            tooltipText="Find Text"
            id="find_text"
            align="right"
          ></e-item>
        </e-items>
      </ejs-toolbar>
    </div>
    <div>
      <div id="textSearchToolbar" [style.display]="'none'">
        <div
          class="e-pv-search-bar"
          id="container_search_box"
          [style.top]="'97px'"
          [style.right]="'0px'"
        >
          <div
            class="e-pv-search-bar-elements"
            id="container_search_box_elements"
          >
            <div
              class="e-input-group e-pv-search-input"
              id="container_search_input_container"
            >
              <input
                class="e-input"
                id="container_search_input"
                type="text"
                placeholder="Find in document"
                (keypress)="searchInputKeypressed($event)"
              />
              <span
                class="e-input-group-icon e-input-search-group-icon e-icons e-search"
                id="container_search_box-icon"
                style="top: 4px;"
                (click)="initiateTextSearch()"
              ></span>
              <span
                class="e-input-group-icon e-input-search-group-icon e-icons e-close"
                id="container_close_search_box-icon"
                [style.display]="'none'"
                style="top: 4px;"
                (click)="clearTextSearch()"
              ></span>
            </div>
            <button
              class="e-btn e-icon-btn e-pv-search-btn e-icons e-chevron-left"
              id="container_prev_occurrence"
              (click)="previousTextSearch()"
              type="button"
              [disabled]="true"
              aria-label="Previous Search text"
            ></button>
            <button
              class="e-btn e-icon-btn e-pv-search-btn e-icons e-chevron-right"
              id="container_next_occurrence"
              type="button"
              (click)="nextTextSearch()"
              [disabled]="true"
              aria-label="Next Search text"
            ></button>
            <button
              id="container_search_box-icon"
              style="top: 4px;"
              type="button"
              (click)="findText($event)"
            >
              Close
            </button>
          </div>
          <div
            class="e-pv-match-case-container"
            id="container_match_case_container"
          >
            <div class="e-checkbox-wrapper e-wrapper e-pv-match-case">
              <label for="container_match_case">
                <input
                  id="container_match_case"
                  type="checkbox"
                  class="e-control e-checkbox e-lib"
                  (click)="checkBoxChanged($event)"
                />
                <span class="e-ripple-container" data-ripple="true"></span>
                <span id="checkboxSpan" class="e-icons e-frame"></span>
                <span class="e-label">Match case</span>
              </label>
            </div>
          </div>
        </div>
      </div>
      <ejs-pdfviewer
        #pdfviewer
        id="pdfViewer"
        [documentPath]="document"
        [resourceUrl]="resource"
        [enableAnnotationToolbar]="false"
        [enableCommentPanel]="false"
        [enableToolbar]="false"
        [enableNavigationToolbar]="false"
        (documentLoad)="documentLoaded($event)"
        style="height:640px; display: block"
      >
      </ejs-pdfviewer>
    </div>
  </div>
</div>

Customize the Search Box Behavior
app.component.ts

In the component’s TypeScript file (app.component.ts), implement the findText() function to toggle the visibility of the search box, and add a function to close the search box (clearTextSearch()).

import {
  Component,
  ViewEncapsulation,
  OnInit,
  ViewChild,
  Inject,
} from '@angular/core';
import {
  PdfViewerComponent,
  LinkAnnotationService,
  BookmarkViewService,
  MagnificationService,
  ToolbarService,
  NavigationService,
  TextSelectionService,
  PrintService,
  DynamicStampItem,
  SignStampItem,
  StandardBusinessStampItem,
  PageChangeEventArgs,
  LoadEventArgs,
  AnnotationService,
  FormDesignerService,
  PageOrganizerService,
  TextSearchService,
  TextSelection,
  PdfViewerModule,
} from '@syncfusion/ej2-angular-pdfviewer';
import {
  ToolbarComponent,
  MenuItemModel,
  ToolbarModule,
  MenuModule,
} from '@syncfusion/ej2-angular-navigations';
import { DialogComponent } from '@syncfusion/ej2-angular-popups';
import { ClickEventArgs } from '@syncfusion/ej2-buttons';
import { SwitchComponent, SwitchModule } from '@syncfusion/ej2-angular-buttons';

/**
 * Default PdfViewer Controller
 */
@Component({
  selector: 'app-root',
  templateUrl: 'app.component.html',
  encapsulation: ViewEncapsulation.None,
  providers: [
    LinkAnnotationService,
    BookmarkViewService,
    TextSearchService,
    TextSelectionService,
    MagnificationService,
    ToolbarService,
    NavigationService,
    TextSelectionService,
    PrintService,
    AnnotationService,
    FormDesignerService,
    PageOrganizerService,
  ],
  styleUrls: ['app.component.css'],
  standalone: true,
  imports: [SwitchModule, ToolbarModule, MenuModule, PdfViewerModule],
})
export class AppComponent {
  @ViewChild('pdfviewer')
  public pdfviewerControl: PdfViewerComponent | undefined;
  @ViewChild('customToolbar')
  public customToolbar: ToolbarComponent | undefined;
  @ViewChild('zoomToolbar')
  public zoomToolbar: ToolbarComponent | undefined;

  public document: string =
    'https://cdn.syncfusion.com/content/pdf/pdf-succinctly.pdf';
  public resource: string =
    'https://cdn.syncfusion.com/ej2/23.2.6/dist/ej2-pdfviewer-lib';
  public matchCase = false;
  constructor() {}
  ngOnInit(): void {
    // ngOnInit function
  }

  public documentLoaded(e: LoadEventArgs): void {
    var searchEle = document.getElementById('container_search_box');
    if(searchEle){
    searchEle.style.top = 'auto';
    }
  }

  public findText(e: MouseEvent): void {
    const textSearchToolbarElement =
      document.getElementById('textSearchToolbar');
    if (textSearchToolbarElement !== null) {
      if (textSearchToolbarElement.style.display === 'block') {
        textSearchToolbarElement.style.display = 'none';
      } else {
        textSearchToolbarElement.style.display = 'block';
      }
    }
  }

  public searchInputKeypressed(event: KeyboardEvent): void {
    if (event.key === 'Enter') {
      this.initiateTextSearch();
    }
  }

  public searchText: string = '';
  public prevMatchCase = false;
  public initiateTextSearch(): void {
    const textsearchPrevElement = document.getElementById(
      'container_prev_occurrence'
    ) as HTMLButtonElement;
    const textsearchNextElement = document.getElementById(
      'container_next_occurrence'
    ) as HTMLButtonElement;
    const textsearchcloseElement = document.getElementById(
      'container_close_search_box-icon'
    ) as HTMLElement;
    const textsearchElement = document.getElementById(
      'container_search_box-icon'
    ) as HTMLElement;

    if (
      textsearchPrevElement &&
      textsearchNextElement &&
      textsearchcloseElement &&
      textsearchElement
    ) {
      textsearchPrevElement.disabled = false;
      textsearchNextElement.disabled = false;
      textsearchcloseElement.style.display = 'block';
      textsearchElement.style.display = 'none';

      if (
        this.searchText !==
          (
            document.getElementById(
              'container_search_input'
            ) as HTMLInputElement
          ).value ||
        this.prevMatchCase !== this.matchCase
      ) {
        if(this.pdfviewerControl)
        this.pdfviewerControl.textSearchModule.cancelTextSearch();
        this.searchText = (
          document.getElementById('container_search_input') as HTMLInputElement
        ).value;
        if(this.pdfviewerControl)
        this.pdfviewerControl.textSearchModule.searchText(
          this.searchText,
          this.matchCase
        );
        this.prevMatchCase = this.matchCase;
      } else {
        this.nextTextSearch();
      }
    }
  }

  public clearTextSearch(): void {
    const textsearchcloseElement = document.getElementById(
      'container_close_search_box-icon'
    ) as HTMLElement;
    const textsearchElement = document.getElementById(
      'container_search_box-icon'
    ) as HTMLElement;
    textsearchcloseElement.style.display = 'none';
    textsearchElement.style.display = 'block';
    if(this.pdfviewerControl)
    this.pdfviewerControl.textSearchModule.cancelTextSearch();
    const searchTextElement = document.getElementById(
      'container_search_input'
    ) as HTMLInputElement;
    searchTextElement.value = '';
  }

  public previousTextSearch(): void {
    if(this.pdfviewerControl)
    this.pdfviewerControl.textSearchModule.searchPrevious();
  }

  public nextTextSearch(): void {
    if(this.pdfviewerControl)
    this.pdfviewerControl.textSearchModule.searchNext();
  }

  public checkBoxChanged(event: Event): void {
    const target = event.target as HTMLInputElement;

    if (target.checked) {
      const matchcaseElement = document.getElementById(
        'container_match_case'
      ) as HTMLInputElement;
      if (matchcaseElement) {
        matchcaseElement.checked = true;
      }
      this.matchCase = true;
      const checkboxSpanElement = document.getElementById('checkboxSpan');
      if (checkboxSpanElement) {
        checkboxSpanElement.classList.add('e-check');
      }
    } else {
      this.matchCase = false;
      const checkboxSpanElement = document.getElementById('checkboxSpan');
      if (checkboxSpanElement) {
        checkboxSpanElement.classList.remove('e-check');
      }
    }
  }
}
Style the Search Box
app.component.css

To ensure the search box and toolbar look good and function as intended, the following custom CSS is used:

/* custom code start*/
#magnificationToolbar {
  background: transparent;
  height: auto;
  min-height: 56px;
  width: 200px;
  border: none;
  position: absolute;
  z-index: 1001;
  bottom: 58px;
  right: 16px;
  transform: rotate(90deg);
}

.e-pv-fit-page-icon::before {
  content: '\e91b';
  font-family: "e-icons";
}

#magnificationToolbar.e-toolbar .e-toolbar-items {
  background: transparent;
}

#magnificationToolbar.e-toolbar .e-tbar-btn {
  border-radius: 50%;
  min-height: 30px;
  min-width: 30px;
  border: 1px solid #c8c8c8;
}

#topToolbar {
  top: 0px;
  z-index: 1001;
}

.e-tbar-section .e-sample-resize-container {
  height: 46px;
}

.e-bookmark-popup {
  height: 200px;
  max-width: 250px;
}

.e-text-search-popup {
  height: 104px;
  max-width: 348px;
}

.e-custom-search-input {
  width: 234px;
}

.e-text-search-popup .e-footer-content, .e-bookmark-popup .e-footer-content {
  padding: 0;
  height: 0;
}

.search-button, .search-button:disabled, .search-button:focus, .search-button:hover  {
  background: transparent;
  box-shadow: none;
}

#popup .e-dlg-content {
  padding-left: 0;
  padding-bottom: 0;
}

.e-pv-bookmarks {
  min-width: 234px;
}

.e-pv-current-page-number {
  width: 46px;
  height: 28px;
  text-align: center;
}

.material .e-pv-current-page-number {
  border-width: 1px;
}
.e-pv-zoom-out-sample {    
  transform: rotate(90deg);
  padding-right: 2px;
}
.customtoolbar.e-toolbar {
background-color: #3f51b5;
width: 50px;
}
.customtoolbar.e-toolbar .e-toolbar-items{
  background-color: #3f51b5;
  height: 40px;  
  display: flex;
  flex-wrap: wrap;
  
}
.e-pv-icon-search::before {
  font-size: 12px;
}
.e-pv-search-input.e-input-group .e-input-search-group-icon.e-input-group-icon {
  background: rgba(0,0,0,0);
}

/* custom code end*/

/* style for slider button*/

.flex-container {
  display: flex;
  justify-content: flex-end;
}

.render-mode-info {
  background: none;
  border: none;
  padding-left: 0px;
}

.render-mode-info .render-mode-info-icon {
  height: 16px;
  width: 16px;
}

.switchLabel {
  font-family: "Segoe UI", "GeezaPro", "DejaVu Serif", sans-serif;        
  font-weight: 400;
  line-height: 20px;
  letter-spacing: 0.24px;
  text-align: right;
  font-size: 14px;
}

.render-mode-info .render-mode-info-icon::before {
  line-height: 0.5rem;
}

.buttonSwitch {
  Width: 40px;
  Height: 24px;
}

.pdfviewer-property-section{
  padding: 20px 15px;
}

.pdfviewer-contextmenu-checkbox-label{
  padding: 10px;
}

.pdfviewer-control-section {
  border-right: 1px solid #D7D7D7;
}

.pdfviewer-property-container{
  padding-bottom: 30px;
}

.header-pdfviewer {
  font-weight: 600;
  padding: 20px 2px;
}

.e-chevron-left::before {
  content: "\e93c"; /* Use the actual content code from your font for the left arrow */
  font-family: "e-icons";
  font-size: 16px; /* Adjust size as needed */
  color: inherit; /* Ensure color is set correctly */
}

.e-chevron-right::before {
  content: "\e93d"; /* Use the actual content code from your font for the right arrow */
  font-family: "e-icons";
  font-size: 16px; /* Adjust size as needed */
  color: inherit; /* Ensure color is set correctly */
}
Key Features Used in the Code:
  1. Custom Toolbar: The custom toolbar is used to trigger the search functionality with the Find Text button. This button toggles the visibility of the search box.
  2. Text Search Toolbar: The search toolbar contains input fields and icons for searching within the document. The user can close the search box by clicking the Close button.
  3. Dynamic Search Box Toggle: The search box can be shown or hidden by clicking the Find Text button, and the user can cancel the search by clicking the Close button.
Sample Link:

You can find the full sample in our GitHub repository.

Conclusion:

I hope you enjoyed learning how to close the search box in the custom toolbar of the Syncfusion PDF Viewer component. By following the steps above, you can easily implement a search functionality that allows users to open and close the search box in the Angular PDF Viewer.

You can refer to Angular PDF Viewer feature tour page to know about its other groundbreaking feature representations and documentation, and how to quickly get started for configuration specifications. You can also explore our Angular PDF Viewer Example to understand how to create and manipulate data.

For current customers, you can check out our components from the License and Downloads page. If you are new to Syncfusion, you can try our 30-day free trial to check out our other controls.

If you have any queries or require clarifications, please let us know in the comments section below. You can also contact us through our support forums, Direct-Trac, or feedback portal. We are always happy to assist you!

Did you find this information helpful?
Yes
No
Help us improve this page
Please provide feedback or comments
Comments (0)
Please  to leave a comment
Access denied
Access denied