Как объединить cdk Virtual Scroll с cdkTable?

Вызвать код с двумя значениями float, код работает в любом диапазоне.

float rand_FloatRange(float a, float b)
{
    return ((b - a) * ((float)rand() / RAND_MAX)) + a;
}
0
задан msanford 15 April 2019 в 20:17
поделиться

2 ответа

Поскольку я не мог найти реально работающее решение, я написал свой «быстрый и грязный» код для фиксированного заголовка. Тем не менее, я надеюсь найти гораздо лучший путь в будущем. Возможно, следующая версия Cdk предложит решение.

Теперь я написал директиву (более или менее хакерскую), которая клонирует таблицу из cdk-virtual-scroll-viewport и размещает клонированный узел раньше. На следующем шаге элемент visibility элемента table thead устанавливается на collapse.

Использование:

<cdk-virtual-scroll-viewport [itemSize]="30" cloneThead>
    <table class="table table-hover">
        <thead>
            ...
        </thead>
        <tbody>
            <tr *cdkVirtualFor="let item of list">
                <td>...</td>
                ...
            </tr>
        </tbody>
    </table>
</cdk-virtual-scroll-viewport>

Директива cloneThead довольно проста:

import { Directive, AfterViewInit, ElementRef } from '@angular/core';

@Directive({
    selector: '[cloneThead]'
})

export class CloneDirective implements AfterViewInit{

    constructor(private el: ElementRef) {}

    ngAfterViewInit(){
        let cloned = this.el.nativeElement.cloneNode(true);

        let table = cloned.querySelector("table");
            table.style.position = 'sticky';
            table.style.top = '0';
            table.style.zIndex = '100';

        this.el.nativeElement.appendChild(table);
    }
}

Это работает довольно хорошо, но имеет еще одну большую проблему: Клон создается после ngAfterViewInit, что приводит к тому, что строки таблицы cdkVirtualFor еще не созданы для DOM.

Это хорошо для самого клона, потому что он еще не содержит tr элементов tbody, НО вычисленные стили CSS для правильной ширины для элементов th также не известен.

Таким образом, все элементы th должны иметь атрибут ширины CSS. В противном случае ширина th и td могут различаться - что выглядит ужасно ...

Может быть, у кого-то еще есть решение сделать «настоящий» клон, после того как cdk-virtual-scroll-viewport -таблица была нарисована.

0
ответ дан Lars Hagen 15 April 2019 в 20:17
поделиться

Вот обновленное решение

. Большая проблема предыдущего кода заключалась в том, что он не мог динамически вычислять ширину столбцов. Поэтому необходимо было указать с каждым столбцом.

Эта версия исправляет эту проблему.

@Directive({
  selector: '[cdkFixedHeader]'
})

export class FixedHeaderDirective implements AfterViewInit{

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

    ngAfterViewInit(){

        // get the viewport element
        let cdkViewport = this.el.nativeElement.closest("cdk-virtual-scroll-viewport");

        // check if table was already cloned
        let clonedHeader = cdkViewport.querySelectorAll('.cloned-header');

        // create a clone if not exists
        if (clonedHeader.length == 0)
        {
            let table = this.el.nativeElement.closest('table');
            let cloned = table.cloneNode(true);
                cloned.style.position = 'sticky';
                cloned.style.top = '0';
                cloned.style.zIndex = '100';

            // remove tbody with elements
            let tbody = cloned.querySelector('tbody');
            cloned.removeChild(tbody);

            // add a "helper" class
            this.renderer.addClass(cloned, "cloned-header");

            // append cloned object to viewport
            cdkViewport.appendChild(cloned);
        }       
        // 
        //  walk through all <tr> with their <td> and store the max value in an array
        //
        let width = [];
        let td = this.el.nativeElement.querySelectorAll("td");
        width = new Array(td.length).fill(0);

        td.forEach((item,index) => {
            const w = item.getBoundingClientRect().width;
            width[index] = Math.max(w, width[index]);
        })  
        // 
        //  get <th> elements and apply the max-width values
        //
        let th = cdkViewport.querySelectorAll('.cloned-header th');
        th.forEach((item,index) => {
            this.renderer.setStyle(item, "min-width", width[index] + 'px')
        })
    }
}

Использование:

Использование немного изменилось, потому что это было необходимо для вызова директивы, когда обрабатывается *cdkVirtualFor.

<tr *cdkVirtualFor="let item of list" cdkFixedHeader>
    ...
</tr>

Вот и все! Не очень хорошо, но работает ...

0
ответ дан Ashish Kamble 15 April 2019 в 20:17
поделиться
Другие вопросы по тегам:

Похожие вопросы: