Angular PrimeNG Table sticky 사례

PrimeNG Table Sticky 사용 방법

  • 먼저 불평, 정부에서 준 코드가 Angular8RxJS6 버전에 호환되는 문제가 있는데 주로 RxJS6가 많다breaking changes. 다음에 자신이 검증한 코드가 붙어있다. - 2019년 7월 30일 13:15:31
  • 제작 지령:
    
    import { Directive, Input, Renderer, ElementRef, AfterViewInit, OnDestroy, OnChanges } from '@angular/core';
    import { Subscription,fromEvent } from 'rxjs';
    
    @Directive({
        selector: '[stickyHeader]'
    })
    
    export class StickyHeaderDirective implements AfterViewInit, OnDestroy, OnChanges{
    
        private windowScrollSubscription: Subscription = null;
        private windowResizeSubscription: Subscription = null;
        private header: any = null;
        private offsetTop: number = 0;
        private lastScroll: number = 0;
        private isSticky: boolean = false;
        private hasHeader: boolean = false;
        private headerTop = 0;
        @Input('stickyClass') stickyClass: string = "";
        @Input('stickyTop') stickyTop: number = 0;
    
        constructor(private elementRef: ElementRef, private renderer: Renderer) {
    
        }
    
        ngAfterViewInit(): void {
            setTimeout(()=>{
                this.windowScrollSubscription = fromEvent(window, 'scroll').subscribe(() => this.manageScrollEvent());
                this.windowResizeSubscription = fromEvent(window, 'resize').subscribe(() => this.updateHeaderSize());
                const headers = this.elementRef.nativeElement.getElementsByTagName('TR');
                this.hasHeader = headers.length > 0;
                if (this.hasHeader) {
                    this.header = headers[0];
                    this.headerTop = this.header.getBoundingClientRect()['top'];
                    this._calcPosition();
                }
            }, 0);
        }
    
        ngOnDestroy(): void {
            if (this.windowScrollSubscription){
                this.windowScrollSubscription.unsubscribe();
                this.windowScrollSubscription = null;
            }
            if (this.windowResizeSubscription){
                this.windowResizeSubscription.unsubscribe();
                this.windowResizeSubscription = null;
            }
        }
    
        ngOnChanges(changes)
        {
            if (changes.stickyTop) {
                this._calcPosition();
            }
        }
    
        private _calcPosition(){
            if (this.hasHeader) {
                const scroll = window.pageYOffset;
                if (this.isSticky && scroll >= this.headerTop) {
                    this.header.style.top =  this.stickyTop + 'px';
                }
            }
        }
    
        private manageScrollEvent(): void {
            const scroll = window.pageYOffset;
            if (scroll > this.lastScroll && !this.isSticky && scroll >= this.offsetTop) {
                this.setSticky();
            } else if (scroll < this.lastScroll && this.isSticky && scroll <= this.offsetTop) {
                this.unsetSticky();
            }
            this.lastScroll = scroll;
        }
    
        private setSticky(): void {
            this.isSticky = true;
            this.header.style.position = 'fixed';
            this.header.style.top =  this.stickyTop + 'px';
            this.header.style.display = 'table';
            this.updateHeaderSize();
            this.setClass(true);
        }
    
        private updateHeaderSize(){
            if (this.isSticky) {
                const tableWidth = this.elementRef.nativeElement.getBoundingClientRect()['right'] - this.elementRef.nativeElement.getBoundingClientRect()['left'];
                this.header.style.width = tableWidth + 'px';
                // update size of TH elements
                const thArray = this.elementRef.nativeElement.getElementsByTagName('TH');
                for (let i = 0; i < thArray.length; i++){
                    thArray[i].style.width = tableWidth / thArray.length + "px";
                }
                
            }
        }
    
        private unsetSticky(): void {
            this.isSticky = false;
            this.header.style.position = 'static';
            this.header.style.width = 'auto';
            this.header.style.display = 'table-row';
            this.setClass(false);
        }
    
        private setStyle(key: string, value: string): void {
            this.renderer.setElementStyle(this.header, key, value);
        }
    
        private setClass(add: boolean): void {
            if (this.stickyClass){
                this.renderer.setElementClass(this.header, this.stickyClass, add);
            }
        }
    
    }
  • 제작된 명령을 구성 요소가 있는 모듈로 가져오기
  • 템플릿에 사용sticky 명령:
  • 위에 주석된 속성 [stickyTop]=50 은 밑에 있는 열 헤더의 예를 지정할 수 있습니다.
  • 설정css스타일:
    .header{
        height: 50px;
        width: 100%;
        background-color:cornflowerblue;
        color: white;
        font-size: 16px;
        font-weight: bold;
        font-family: Arial;
        line-height: 50px;
        text-align: center;
        border-bottom: 1px solid #666666;
        position: fixed;
        z-index: 1;
        top: 0px;
    }
    p-dataTable{
        margin-left: 20px;
        margin-top: 50px;
        margin-right: 20px;
        display: block;
    }
    
    :host /deep/ p-datatable .stickyHeader{
      box-shadow: 2px 2px 1px #888888;
    }
  • 최종 효과
  • 공식 코드의 호환되지 않는 문제를 수정한다:
  • 좋은 웹페이지 즐겨찾기