Ngx-datatable: column header misalignment with body in version 11.1.2 ( same code works in 11.0.4 )

Created on 22 Nov 2017  Â·  24Comments  Â·  Source: swimlane/ngx-datatable








I'm submitting a ... (check one with "x")

[x] bug report => search github for a similar issue or PR before submitting
[ ] feature request
[ ] support request => Please do not submit support request here, post on Stackoverflow or Gitter

Current behavior
With the same typescript code on my side, I have a different rendering depending on ngx-datatable version I use :

This is what I have with ngx-datatable version 11.0.4
list-11 0 4

and with version 11.1.2
list-11 1 2

Expected behavior
Same rendering regardless of version

Reproduction of the problem

my-list component :

html

<ngx-datatable
    class="material fullscreen"                        
    [columnMode]="'force'"
    [rowClass]="getRowClass"
    [headerHeight]="50"
    [footerHeight]="50"
    [rowHeight]="50"
    [externalPaging]="true"
    [externalSorting]="true"
    [loadingIndicator]="loading"
    [limit]="pageSize"
    [offset]="pageOffset"
    [count]="totalCount"
    [rows]="items"
    [columns]="columns"
>

    <!-- Header template -->
    <ng-template #headerTemplate let-column="column">
        <span class="datatable-header-cell-wrapper"><span class="datatable-header-cell-label draggable text-truncate" (click)="sort()">{{ column.name | translate }}</span></span>
    </ng-template>

    <!-- Cell template -->
    <ng-template #cellTemplate let-column="column" let-value="value">
        <div [innerHTML]="getCellHtml(value, column) | safe: 'html'"></div>
    </ng-template>

    <!-- Actions template -->
    <ng-template #actionTemplate let-row="row" let-value="value">
        <!-- Buttons omitted -->
    </ng-template>

</ngx-datatable>

typescript

@Component({
  selector: 'my-list',
  [...]
})
export class MyListComponent implements OnInit, OnDestroy {
    @Input('searchFn') searchFn: (term: string) => Observable<any>;
    @Input('columnFn') columnFn: () => Observable<Columns[]>;
    @Input('getCellFn') getCellFn: (column: string, value: string) => string;
    [...]
    constructor(private el: ElementRef, private sanitizer: DomSanitizer) {}

    public ngOnInit() {
        // on init, get columns and then do search
        this._column().then(() => this._search(''));
    }

    private getCellHtml(value, column) : string
    {
        const type = typeof value;

        // Allow for column custom text
        if (this.getCellFn !== undefined) {
            var innerHtml = this.getCellFn(column.prop, value);
            if (innerHtml !== undefined)
                return innerHtml;
        }

        switch (type) {
            case 'string': {
                if (moment(value, moment.ISO_8601).isValid()) {
                    return moment(value).local().format('L');
                } else {
                    const sanitizedValue = this.sanitizer.sanitize(SecurityContext.HTML, value);
                    return `<span class="text-truncate">${sanitizedValue}</span>`;
                }
            }
            case 'boolean': {
                return value ? '<i class="material-icons">check</i>' : '';
            }
        }

        // Any other case, return value as is
        return value;
    }

    private _search(term: string) {
        this.searchFn(term).subscribe(result => this.items = [...result.items]);
    }

    private _column() {
        const promise = new Promise((resolve, reject) => { 

            this.columns = []

            this.columnFn()
                .flatMap(preferences => preferences) // yield array items
                .map(preference => {
                    return {
                        headerTemplate: this.headerTemplate,
                        cellTemplate: this.cellTemplate,
                        name: preference.description,
                        prop: preference.fieldName,
                        sortable: true,
                        draggable: true,
                        minWidth: undefined,
                        maxWidth: undefined,
                        _index: preference.fieldOrder
                    };
                })
                .toArray()
                .subscribe(
                    result => {
                        result.sort((a, b) => a._index - b._index)
                        result.push({
                            headerTemplate: this.headerTemplate,
                            cellTemplate: this.actionTemplate,
                            name: '',
                            prop: 'id',
                            sortable: false,
                            draggable: false,
                            minWidth: 100,
                            maxWidth: 100,
                            _index: result.length
                        });
                        this.columns = [...result];

                        // Resolve promise
                        resolve();
                    }
                );

        });
        return promise;
    }

}

Consuming my-list component :

html

<my-list #myList
    sortProp="'name'"
    [columnFn]="getColumnCallback"
    [getCellFn]="formatCellCallback">
</my-list>

typescript

    [...]

    /**
     * Return Observable of items from api service
     * Note: Notation 'public xxx = () => {}' is required in order to work correctly
     */
    public searchCallback = (term: string): Observable<any> => {
        return this.myHttpApiService.search(term);
    }


    /**
     * Return columns preferences Observable from api service
     * Note: Notation 'public xxx = () => {}' is required in order to work correctly
     */
    public getColumnCallback = () => {
        return this.myHttpApiService.getFormPreferences();
    }


    /**
     * Basic formatting is handled by MyListComponent. This handler is exclusively if you want to intercept columns
     * of 'string' type and format it as you need.
     * 
     * Note: Notation 'public xxx = () => {}' is required in order to work correctly ( This keeps 'this' valid )
     */
    public formatCellCallback = (column: string, value: string): string => {
        switch (column) {
            case 'gender': return this.getGenderIcon(value);
            case 'type': return this.getTypeLabel(value);
            default: return undefined;
        }
    }
    [...]

Please tell us about your environment:

windows 10 pro, vs code, npm, node

  • Table version: 0.8.x

    11.0.4 vs 11.1.2

  • Angular version: 2.0.x

    5.0.2

  • Browser: [all | Chrome XX | Firefox XX | IE XX | Safari XX | Mobile Chrome XX | Android X.X Web Browser | iOS XX Safari | iOS XX UIWebView | iOS XX WKWebView ]

    Chrome

  • Language: [all | TypeScript X.X | ES6/7 | ES5]
    typescript 2.6.1

Most helpful comment

Is this the same issue, or different? If it's different, I will log a new issue.

screencastgif

All 24 comments

This might not be related but I am facing the same issue on version 9.3.1. It happens only when the table is inside md-tab. It will auto correct itself when I try to resize any column or when I wrap it in *ngIf

As a matter of fact I am within a mat-tab too.. This works fine on version 11.0.4, but not on 11.1.2.
ps: I saw that there is a version 11.1.3 but change logs shows nothing in regards to this particular issue.

@darkurse any luck with a solution?

No, I was actually waiting for a suggestion from @amcdnl . I kind of suspect the force rendering mode.
I actually went back to 11.0.4.

Now I actually face a new issue with the force rendering : I need to print the datatable and because the column width are forced, my print view is larger than my paper. Therefore I am gonna try the flex mode again and let you know how it goes.

@darkurse I am curious if you got it working. Flex doesnt work in my case. Only thing that works for me is creating "custom" tabs with ngIf.

@realshadow , no dice. Not working well. Seems like force is the only viable way up to 11.0.4. Thereafter things don't work well I'm afraid.

I see this issue every time when the width and the maxWidth column's attributes have different values. Making them equal fix it.

I have the same issue when I add a new column to the existing table. After I scroll left or down the columns align to the correct location.

I was just able to fix this by setting the width, minWidth and maxWidth to the same value.

That's interesting. I'm curious to know what the contributors say about it. Do you think this would also fix the frozenLeft, frozenRight issues ?

@darkurse I try adding the frozenLeft or frozenRight to my code and that does not fixes it. I still see all the other columns on top of the frozenLeft or frozenRight columns.

@hiper2d , @enniob . To give continuity to this thread, I think I found the source of the issue and offer a solution in issue #1165. I also made a PR which hopefully is the fix or at least can give a hint towards the right solution..

@amcdnl, could you make a new release ? It's been a long time and lots of PR have been made since then.
Thanks in advance

@amcdnl, could you please make a new release ?

Showing the datatable to customers with these horrible collapsed column headers is terrible !!

I've sent you a private message 2 weeks ago regarding this and the above message. I don't want to be a pain in the neck, but a simple yay or nay answer would be welcome !

Thank you

Released 11.2.0

Still not working in 11.2.0

Is this the same issue, or different? If it's different, I will log a new issue.

screencastgif

Its not the same issue, this happens when I add and remove columns to my
table.

Here you can see that the columns do not line up.

capture2

Here is the table in the original state before I add the new columns.

capture

But when I scroll to the left all the columns line up correctly.

Thanks

On Thu, Mar 1, 2018 at 1:08 PM, Stewart Rand notifications@github.com
wrote:

Is this the same issue, or different? If it's different, I will log a new
issue.

[image: screencastgif]
https://user-images.githubusercontent.com/6986171/36861325-f063cc92-1d59-11e8-9381-ddb50d6f0f5e.gif

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/swimlane/ngx-datatable/issues/1145#issuecomment-369679077,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AFCZo6b2JpBZw8UxDNaJNIAVrL0fp6ezks5taDkDgaJpZM4QnM3u
.

@enniob Can't see your images

@stewx just uploaded the image, I had replies to the email and it didn't attached it.

I get the same issue also when I change the display columns but if I have a scroll and scroll left it goes away. So looks like it is an issue with table refresh or columns recalculation.

@pedrocleto is there a way to force a refresh? I'm calling this.datatable.recalculate(); but its not doing anything. A quick solution I used on my application was to clear all the data on the table and add it again.

In my case I was using the columns array to drive the datatable. I simply moved the initialization of the columns array to after the rows array was populated, and it started working correctly.

For anyone still encountering this issue of misaligned headers to data rows at init:

In my scenario I was using angular flex layout library with property 'fxFlex="100"' assigned to the component.

This got fixed by simply moving the 'fxFlex' property on a wrapper

. Doesn't seem to play nicely with angular flex.

Hope this helps.

Was this page helpful?
0 / 5 - 0 ratings