Descripción general de la directiva de resaltado de texto de Angular

    The IgxTextHighlightDirective and IgxTextHighlightService in Ignite UI for Angular are used to highlight parts of a text, providing options for case sensitive searches and to highlight only exact matches. They allow the developer to keep an active highlight, which can be any of the already highlighted parts.

    Angular Text Highlight Directive Example

    Getting Started with Ignite UI for Angular Text Highlight Directive

    Para comenzar con la directiva Ignite UI for Angular Text Highlight, primero debe instalar Ignite UI for Angular. En una aplicación Angular existente, escriba el siguiente comando:

    ng add igniteui-angular
    

    Para obtener una introducción completa al Ignite UI for Angular, lea el tema de introducción.

    The next step is to import the IgxTextHighlightModule in your app.module.ts file.

    // app.module.ts
    ...
    import { IgxTextHighlightModule } from 'igniteui-angular/directives';
    // import { IgxTextHighlightModule } from '@infragistics/igniteui-angular'; for licensed package
    
    @NgModule({
        ...
        imports: [IgxTextHighlightModule],
        ...
    })
    export class AppModule {}
    

    Alternatively, as of 16.0.0 you can import the IgxTextHighlightDirective as a standalone dependency.

    // home.component.ts
    
    import { IgxTextHighlightDirective, IgxTextHighlightService } from 'igniteui-angular/directives';
    // import { IgxTextHighlightDirective, IgxTextHighlightService } from '@infragistics/igniteui-angular'; for licensed package
    
    @Component({
      selector: 'app-home',
      template: `
        <div
          igxTextHighlight
          [value]="html"
          [groupName]="'group1'"
          [containerClass]="'search-text'"
          class="search-text"
        >
          {{ html }}
        </div>
      `,
      styleUrls: ['home.component.scss'],
      standalone: true,
      imports: [IgxTextHighlightDirective],
    })
    export class HomeComponent {
      constructor(public textHighlightService: IgxTextHighlightService) {}
    }
    

    Now that you have the Ignite UI for Angular Text Highlight module or directive imported, you can start using the igxTextHighlight.

    Using the Angular Text Highlight Directive

    Vamos a crear un cuadro de búsqueda que podamos usar para resaltar diferentes partes del texto. Usaremos el componente InputGroup de Ignite UI for Angular en el que agregaremos una entrada de texto con botones para borrar coincidencias, buscar siguiente, buscar anterior y un botón para especificar si la búsqueda distinguirá entre mayúsculas y minúsculas o no. Además, tiene una etiqueta para cuántas coincidencias hemos encontrado.

    <div class="search-container">
      <igx-input-group type="search" class="input-group">
        <igx-prefix>
          <igx-icon *ngIf="searchText.length == 0">search</igx-icon>
          <igx-icon *ngIf="searchText.length > 0" (click)="clearSearch()"
            >clear</igx-icon
          >
        </igx-prefix>
    
        <input
          #search1
          id="search1"
          igxInput
          placeholder="Search"
          autocomplete="off"
          [(ngModel)]="searchText"
          (ngModelChange)="onTextboxChange()"
          (keydown)="searchKeyDown($event)"/>
        <igx-suffix>
          <div class="caseSensitiveButton">
            <button
              igxIconButton="flat"
              igxRipple
              igxRippleCentered="true"
              (click)="updateSearch()"
              [style.background]="caseSensitive ? 'rgb(73, 180, 254)' : 'transparent'">
              <igx-icon class="caseSensitiveIcon" fontSet="material">text_fields</igx-icon>
            </button>
          </div>
          <ng-container *ngIf="searchText.length > 0">
            <span>
              <ng-container *ngIf="matchCount > 0">
                {{ index + 1 }} of {{ matchCount }} results
              </ng-container>
              <ng-container *ngIf="matchCount == 0"> No results </ng-container>
            </span>
          </ng-container>
    
          <div class="searchButtons">
            <button
              igxIconButton="flat"
              igxRipple
              igxRippleCentered="true"
              (click)="findPrev()"
              [disabled]="!canMoveHighlight">
              <igx-icon fontSet="material">navigate_before</igx-icon>
            </button>
            <button
              igIconButton="flat"
              igxRipple
              igxRippleCentered="true"
              (click)="findNext()"
              [disabled]="!canMoveHighlight">
              <igx-icon fontSet="material">navigate_next</igx-icon>
            </button>
          </div>
        </igx-suffix>
      </igx-input-group>
    </div>
    

    Luego, agregaremos un div con texto y la directiva IgxTextHighlight. Tenga en cuenta que, dado que necesitamos vincular la entrada del valor al texto en el div, también usaremos la interpolación para el texto del div.

    <div
      igxTextHighlight
      [value]="html"
      [groupName]="'group1'"
      [containerClass]="'search-text'"
      class="search-text">
       {{html}}
    </div>
    

    En el archivo .ts de nuestro componente, primero debemos agregar los siguientes campos, que se utilizan para los enlaces en la plantilla de nuestro componente:

    @Component({
        ...
    })
    export class HomeComponent {
        public html = '...';
    
        @ViewChild(IgxTextHighlightDirective, {read: IgxTextHighlightDirective})
        public highlight: IgxTextHighlightDirective;
    
        public searchText: string = '';
        public matchCount: number = 0;
        public caseSensitive: boolean = false;
        public index: number = 0;
    
        public get canMoveHighlight() {
            return this.matchCount > 1;
        }
    }
    

    Luego, debemos agregar los siguientes métodos que permitirán al usuario aplicar resaltados al texto que ha escrito en el cuadro de búsqueda y mover el resaltado activo.

    @Component({
        ...
    })
    export class HomeComponent {
        constructor(public textHighlightService: IgxTextHighlightService) {}
    
        public searchKeyDown(ev) {
            if (this.searchText) {
                if (ev.key === 'Enter' || ev.key === 'ArrowDown' || ev.key === 'ArrowRight') {
                    ev.preventDefault();
                    this.findNext();
                } else if (ev.key === 'ArrowUp' || ev.key === 'ArrowLeft') {
                    ev.preventDefault();
                    this.findPrev();
                }
            }
        }
    
        public onTextboxChange() {
            this.index = 0;
            this.find(0);
        }
    
        public updateSearch() {
            this.caseSensitive = !this.caseSensitive;
            this.find(0);
        }
    
        public clearSearch() {
            this.searchText = '';
            this.find(0);
        }
    
        private findNext() {
            this.find(1);
        }
    
        private findPrev() {
            this.find(-1);
        }
    
        private find(increment: number) {
            if (this.searchText) {
                this.matchCount = this.highlight.highlight(this.searchText, this.caseSensitive);
                this.index += increment;
    
                this.index = this.index < 0 ? this.matchCount - 1 : this.index;
                this.index = this.index > this.matchCount - 1 ? 0 : this.index;
    
                if (this.matchCount) {
                    this.textHighlightService.setActiveHighlight('group1', {
                        columnIndex: 0,
                        index: this.index,
                        page: 0,
                        rowIndex: 0
                    });
                }
            } else {
                this.highlight.clearHighlight();
            }
        }
    }
    

    Si la muestra está configurada correctamente, el resultado final debería verse así:

    Search across multiple elements

    The igxTextHighlight allows you to search across multiple elements which all share one active highlight. This is done by having the same groupName value across multiple TextHighlight directives. In order to setup the sample we will reuse the search box from the previous sample, but this time we will add two div elements. The column and row inputs are useful when you have multiple elements and in our case the second div has a different row value.

    <div
      igxTextHighlight
      [groupName]="'group1'"
      [row]="0"
      [containerClass]="'search-text'"
      [value]="firstParagraph"
      class="search-text">
       {{firstParagraph}}
    </div>
    <div
      igxTextHighlight
      [groupName]="'group1'"
      [row]="1"
      [containerClass]="'search-text'"
      [value]="secondParagraph"
      class="search-text">
       {{secondParagraph}}
    </div>
    

    In the .ts file we have the firstParagraph and secondParagraph fields, which are bound to the respective value inputs of the text highlight directives. Also, we will now use ViewChildren instead of ViewChild to get all the highlights in our template.

    public firstParagraph = "...";
    
    public secondParagraph = "...";
    
    @ViewChildren(IgxTextHighlightDirective)
    public highlights;
    

    Todo el resto del código en el archivo .ts es idéntico al ejemplo de elemento único con la excepción del método de búsqueda. Los cambios en este método son necesarios ya que ahora tenemos varios elementos, pero el código allí se puede usar independientemente de la cantidad de directivas TextHighlight que tenga en su página.

    @Component({
        ...
    })
    export class HomeComponent {
        constructor(public textHighlightService: IgxTextHighlightService) {}
    
        private find(increment: number) {
            if (this.searchText) {
                let count = 0;
                const matchesArray = [];
    
                this.highlights.forEach((h) => {
                    count += h.highlight(this.searchText, this.caseSensitive);
                    matchesArray.push(count);
                });
    
                this.matchCount = count;
    
                this.index += increment;
                this.index = this.index < 0 ? this.matchCount - 1 : this.index;
                this.index = this.index > this.matchCount - 1 ? 0 : this.index;
    
                if (this.matchCount) {
                    let row;
    
                    for (let i = 0; i < matchesArray.length; i++) {
                        if (this.index < matchesArray[i]) {
                            row = i;
                            break;
                        }
                    }
    
                    const actualIndex = row === 0 ? this.index : this.index - matchesArray[row - 1];
    
                    this.textHighlightService.setActiveHighlight('group1', {
                        index: actualIndex,
                        rowIndex: row
                    });
                }
            } else {
                this.highlights.forEach((h) => {
                    h.clearHighlight();
                });
                this.matchCount = 0;
            }
        }
    }
    

    Styles

    The IgxTextHighlight directive can be styled in terms of changing the color and the background of all occurrences of the given string. To get started, we need to import the index file, where all the theme functions and component mixins live:

    @use "igniteui-angular/theming" as *;
    
    // IMPORTANT: Prior to Ignite UI for Angular version 13 use:
    // @import '~igniteui-angular/lib/core/styles/themes/index';
    

    Following the simplest approach, we create a new theme that extends the highlight-theme and accepts the $resting-background, $resting-color, $active-background and the $active-color parameters.

    $dark-highlight: highlight-theme(
      $resting-background: #ffcd0f,
      $resting-color: #292826,
      $active-background: #292826,
      $active-color: #ffcd0f,
    );
    

    The $resting-background and the $resting-color parameters will be applied to all highlighted occurrences, except for the active highlighted string, which will be styled based on the $active-background and the $active-color parameters.

    El último paso es incluir el tema recién creado.

    :host {
      ::ng-deep {
        @include css-vars($dark-highlight);
      }
    }
    
    Note

    If the component is using an Emulated ViewEncapsulation, it is necessary to penetrate this encapsulation using ::ng-deep to apply the styles.

    Custom styles

    Let's say we want to provide an even richer styling to our highlighted text parts. In order to do this, we can take advantage of the cssClass and the activeCssClass inputs of the IgxTextHighlight directive. We can combine these classes with the styles from the highlight-theme and provide an awesome experience to our users!

    Todo lo que tenemos que hacer es crear un par de clases CSS con algunas propiedades y adjuntarlas usando las entradas anteriores:

    <div
      igxTextHighlight
      [cssClass]="'custom-highlight'"
      [activeCssClass]="'custom-active-highlight'">
       {{html}}
    </div>
    
    // cssClass
    .custom-highlight {
      border: 1px solid #ffcd0f;
    }
    // activeCssClass
    .custom-active-highlight {
      box-shadow: 0 0 3px 0 rgba(0, 0, 0, 0.75);
    }
    

    Como mencionamos anteriormente, incluso podemos combinarlos con un tema:

    :host {
      ::ng-deep {
        @include css-vars($dark-highlight);  
        
        .custom-highlight {
          border: 1px solid #ffcd0f;
        }  
    
        .custom-active-highlight {
          box-shadow: 0 0 3px 0 rgba(0,0,0, .5);
        }
      }
    }
    

    Demo

    API References

    Para obtener información más detallada sobre la API de la directiva TextHighlight, consulte el siguiente enlace:

    Componentes adicionales que se utilizaron:

    Additional Resources

    Nuestra comunidad es activa y siempre da la bienvenida a nuevas ideas.