How to replace innerHtml by matetrial icon

393 views Asked by At

I want to change the texts by icons, what do I have to do to change the texts by icons ?

I have to find the result like this :

enter image description here

file.ts:

  ngAfterViewInit() {
    this.current.paginator = this.paginator;
    const lastBtn = this.el.nativeElement.querySelector(
      '.mat-paginator-navigation-last'
    );
    if (lastBtn) {
      lastBtn.innerHTML = 'Last';
    }

    const firstBtn = this.el.nativeElement.querySelector(
      '.mat-paginator-navigation-first'
    );
    if (firstBtn) {
      firstBtn.innerHTML = 'First';
    }
  }
2

There are 2 answers

3
IDK4real On

If you want to change the button icons, it is possible to do so.\

In order to do so, we need to alter the html that is being generated by the mat-paginator.

The following directive does it:

@Directive({
  selector: '[customPaginatorIcons]'
})
export class CustomPaginatorIcons implements AfterViewInit {

  constructor(
    private el: ElementRef,
    private renderer2: Renderer2
  ) {}

  ngAfterViewInit(): void {
    this.setFirstIcon();
    this.setPreviousIcon();
    this.setNextIcon();
    this.setLastIcon();
  }

  private replaceSvgWithIcon(
    btn: HTMLButtonElement,
    iconName: string
  ): HTMLSpanElement {
    this.renderer2.removeChild(btn, btn.querySelector('svg'));

    const icon: HTMLSpanElement = this.renderer2.createElement('span');
    this.renderer2.addClass(icon, 'material-icons');
    icon.innerHTML = iconName;

    this.renderer2.appendChild(btn, icon);
    return icon;
  }

  private setFirstIcon(): void {
    const btn = this.el.nativeElement.querySelector(
      '.mat-mdc-paginator-navigation-first'
    );

    if (btn) {
      this.replaceSvgWithIcon(btn, 'skip_previous');
    }
  }

  private setPreviousIcon(): void {
    const btn = this.el.nativeElement.querySelector(
      '.mat-mdc-paginator-navigation-previous'
    );

    if (btn) {
      const icon = this.replaceSvgWithIcon(btn, 'play_arrow');
      this.renderer2.setStyle(icon, 'transform', 'rotate(180deg)');
    }
  }

  private setNextIcon(): void {
    const btn = this.el.nativeElement.querySelector(
      '.mat-mdc-paginator-navigation-next'
    );

    if (btn) {
      this.replaceSvgWithIcon(btn, 'play_arrow');
    }
  }

  private setLastIcon(): void {
    const btn = this.el.nativeElement.querySelector(
      '.mat-mdc-paginator-navigation-last'
    );

    if (btn) {
      this.replaceSvgWithIcon(btn, 'skip_next');
    }
  }
}

Now onto the why.

  • Directive: we create our attribute directive that will adjust the icons of the MatPaginator. Attribute Directives are recommended when we only want to edit the html of something.

  • AfterViewInit: we can only edit the contents of the MatPaginator html after it has been fully initialise. The AfterViewInit lifecycle hook is the best hook for the task.

  • ElementRef: this provides access to the HTML code that our directive is placed on.

  • Renderer2: the recommended utility to modify HTML elements safely. It is the basis that directives like ngStyle and ngClass use being the scenes. We can achieve the same goal by directly editing the DOM elements, however, this may raise errors if we edit it incorrectly.

  • setFirstIcon, setPreviousIcon, setNextIcon, setLasttIcon: these are very similar methods, they search for the button that needs to be updated and if it exists, they call the replaceSvgWithIcon method to perform the actual changes. Only exception to this is the setPreviousIcon method since there is no icon that matches what you want. To achieve the look you want, I rotate the next icon.

  • replaceSvgWithIcon: starts by removing the <svg>...</svg> tag from the button. This is the tag that contains the actual image for the icon, the remaining HTML in the button element is for other things like the ripple. Once the element has been removed, we create a new HTMLSpanElement. It is on this element that we will set the material-icons class (so that it uses the Material Icons), and the value of the icon. After this is done, we append it to the provided button and return it (we return the element in case we want to modify something else that is not generic).

To use this directive, we simply call on the html selector of the paginator:

<mat-paginator 
               ...
               customPaginatorIcons>
</mat-paginator>

The above case is meant for Angular 15. For previous versions, simple remove the '-mdc' from the selectors, like so:

  • '.mat-mdc-paginator-navigation-first' to `'.mat-paginator-navigation-first';
  • '.mat-mdc-paginator-navigation-previous' to '.mat-paginator-navigation-previous';
  • '.mat-mdc-paginator-navigation-next' to '.mat-paginator-navigation-next';
  • '.mat-mdc-paginator-navigation-last' to '.mat-paginator-navigation-last';
0
Eliseo On

You can also get it only with .css

In styles.css

.mat-mdc-paginator-navigation-first svg path{
  d:path("M6.5 18q-.425 0-.713-.288Q5.5 17.425 5.5 17V7q0-.425.287-.713Q6.075 6 6.5 6t.713.287Q7.5 6.575 7.5 7v10q0 .425-.287.712Q6.925 18 6.5 18Zm10.45-1.025l-6.2-4.15q-.45-.3-.45-.825q0-.525.45-.825l6.2-4.15q.5-.325 1.025-.038q.525.288.525.888v8.25q0 .6-.525.9q-.525.3-1.025-.05Z")
}
.mat-mdc-paginator-navigation-previous svg path{
  d:path("M7.05 16.975q-.5.35-1.025.05q-.525-.3-.525-.9v-8.25q0-.6.525-.888q.525-.287 1.025.038l6.2 4.15q.45.3.45.825q0 .525-.45.825Z")
}
.mat-mdc-paginator-navigation-next svg path{
  d:path("M7.05 16.975q-.5.35-1.025.05q-.525-.3-.525-.9v-8.25q0-.6.525-.888q.525-.287 1.025.038l6.2 4.15q.45.3.45.825q0 .525-.45.825Z")
}
.mat-mdc-paginator-navigation-last svg path{
  d:path("M17.5 18q-.425 0-.712-.288q-.288-.287-.288-.712V7q0-.425.288-.713Q17.075 6 17.5 6t.712.287q.288.288.288.713v10q0 .425-.288.712q-.287.288-.712.288ZM7.05 16.975q-.5.35-1.025.05q-.525-.3-.525-.9v-8.25q0-.6.525-.888q.525-.287 1.025.038l6.2 4.15q.45.3.45.825q0 .525-.45.825Z")
}

.mat-mdc-paginator-navigation-previous svg
{
  transform:rotate(180deg) translateX(3px)
}
.mat-mdc-paginator-navigation-next svg
{
  transform:translateX(3px)
}