Filter-basic-chips with resize

mail@pastecode.io avatar
unknown
typescript
a month ago
6.7 kB
1
Indexable
Never
import {
  ChangeDetectorRef,
  Component,
  ElementRef,
  EventEmitter,
  HostListener,
  Input,
  OnChanges,
  OnInit,
  Output,
  SimpleChanges,
  ViewChild,
} from '@angular/core';

import { FilterBasicSelectItem } from '../../../../../../shared';
import { WithStaticLabels } from '../../../../with-static-labels/with-static-labels';

@Component({
  selector: 'app-filter-basic-chips',
  templateUrl: './filter-basic-chips.component.html',
  styleUrls: ['./filter-basic-chips.component.scss'],
})
export class FilterBasicChipsComponent extends WithStaticLabels implements OnInit, OnChanges {
  @Input() selectedItems: FilterBasicSelectItem[] = [];
  @Input() removableChips = true;
  @Input() containerWidth: number;

  @ViewChild('matChipsList') matChipsList: ElementRef;

  @Output() chipRemoved = new EventEmitter<FilterBasicSelectItem>();

  visibleChips: FilterBasicSelectItem[] = [];
  visibleChipCount: number;
  hideChips: boolean;
  hiddenChipCount = 0;

  lastWindowWidth: number;
  initialChipsWidth: Record<string, number> = {};
  private readonly GAP_BETWEEN_CHIPS: number = 8;

  constructor(private changeDetectorRef: ChangeDetectorRef) {
    super();
  }

  ngOnInit(): void {
    this.visibleChips = this.selectedItems;
  }

  ngOnChanges(changes: SimpleChanges): void {
    if (changes.containerWidth?.currentValue) {
      this.setInitialChipsWidth();
      this.calculateOverflownChips();
    }

    if (changes.selectedItems) {
      this.visibleChips = changes.selectedItems.currentValue;
      if (changes.selectedItems.currentValue && changes.selectedItems.previousValue) {
        const currentLength = changes.selectedItems.currentValue.length;
        const prevLength = changes.selectedItems.previousValue.length;

        if (currentLength !== prevLength) {
          // if (changes.selectedItems.currentValue?.length > changes.selectedItems.previousValue?.length) {
          //   //there are new filters, need their width in the record for correct calculation of overflow
          //   // this.changeDetectorRef.detectChanges();
          // }

          this.hideChips = false;
          this.hiddenChipCount = 0;
          if (currentLength > 0 && currentLength < prevLength) {
            this.calculateOverflownChips();
          } else {
            this.changeDetectorRef.detectChanges();
            this.updateChipsWidth();
            this.calculateOverflownChips();
          }
        }
      }
      //selected label -> innertext.includes
    }
  }

  ngAfterViewInit(): void {
    this.lastWindowWidth = window.innerWidth;
    if (this.selectedItems.length && this.containerWidth) {
      this.setInitialChipsWidth();
      this.calculateOverflownChips();
    }
  }

  @HostListener('window:resize', ['$event'])
  onResize(): void {
    const hasWindowIncreased = window.innerWidth > this.lastWindowWidth;

    this.lastWindowWidth = window.innerWidth;
    if (!this.selectedItems.length) {
      return;
    }

    if (hasWindowIncreased) {
      console.log('increase');
      this.showHiddenChips();
    } else {
      console.log('decrease');
      this.calculateOverflownChips();
    }
  }

  onChipRemoved(item: FilterBasicSelectItem): void {
    this.chipRemoved.emit(item);
    delete this.initialChipsWidth[item.selectedLabel];
  }

  setInitialChipsWidth(): void {
    const matChipsWrapper = this.matChipsList.nativeElement.firstChild?.firstChild;

    for (let index = 0; index < this.selectedItems.length; index++) {
      this.initialChipsWidth[this.selectedItems[index].selectedLabel] = matChipsWrapper?.children[index]?.offsetWidth;
    }
  }

  updateChipsWidth(): void {
    const matChipsWrapper = this.matChipsList.nativeElement.firstChild?.firstChild;

    this.visibleChips.forEach(chip => {
      for (let index = 0; index < matChipsWrapper.children.length; index++) {
        if (matChipsWrapper.children[index].innerText.includes(chip.selectedLabel)) {
          this.initialChipsWidth[chip.selectedLabel] = matChipsWrapper.children[index].offsetWidth;
        }
      }
    });
  }

  showHiddenChips(): void {
    if (this.hideChips) {
      const containerWidth = this.matChipsList.nativeElement.parentNode?.parentNode?.parentNode?.offsetWidth;
      const matChipsWrapper = this.matChipsList.nativeElement.firstChild?.firstChild;

      let totalWidth = 0;

      for (let index = 0; index < this.visibleChips.length; index++) {
        totalWidth += matChipsWrapper.children[index].offsetWidth + this.GAP_BETWEEN_CHIPS;
      }

      for (let index = this.visibleChips.length; index < this.selectedItems.length; index++) {
        totalWidth += this.initialChipsWidth[this.selectedItems[index].selectedLabel] + this.GAP_BETWEEN_CHIPS;

        if (totalWidth < containerWidth) {
          this.visibleChipCount++;
          this.visibleChips = this.selectedItems.slice(0, this.visibleChipCount);
          this.hiddenChipCount--;
          if (this.visibleChipCount === this.selectedItems.length) {
            this.hideChips = false;
            this.hiddenChipCount = 0;
          }
        }
      }
    }
  }

  calculateOverflownChips(): void {
    // const matChipsWrapper = this.matChipsList.nativeElement.firstChild?.firstChild;
    const filterBasicDiv = this.matChipsList.nativeElement.parentNode?.parentNode?.parentNode;
    let chipsLength = 0;
    const widthOfExtension = 36;

    for (let index = 0; index < this.selectedItems.length; index++) {
      chipsLength += this.initialChipsWidth[this.selectedItems[index].selectedLabel] + this.GAP_BETWEEN_CHIPS;

      if (chipsLength > filterBasicDiv.offsetWidth) {
        chipsLength -= this.initialChipsWidth[this.selectedItems[index].selectedLabel] + this.GAP_BETWEEN_CHIPS;
        if (chipsLength + widthOfExtension > filterBasicDiv.offsetWidth) {
          index--;
        }

        this.visibleChipCount = index;
        this.hideOverflownChips();
        break;
      }
    }
  }

  hideOverflownChips(): void {
    this.hideChips = true;
    this.visibleChips = this.selectedItems.slice(0, this.visibleChipCount);
    this.hiddenChipCount = this.selectedItems.length - this.visibleChipCount;
    this.changeDetectorRef.detectChanges();
  }

  onShowAllChips(): void {
    this.hideChips = false;
    this.visibleChips = this.selectedItems;
    this.changeDetectorRef.detectChanges();
  }

  onHideChips(): void {
    this.hideChips = true;
    this.visibleChips = this.selectedItems.slice(0, this.selectedItems.length - this.hiddenChipCount);
    this.changeDetectorRef.detectChanges();
  }
}
Leave a Comment