Our blazing fast Grid component built with pure JavaScript


Post by thomasb »

I have an issue with bryntum grid scrolling Sometimes when u scroll up and down data disappeared until I scroll again .
Also the issue appear when I tried to make a customized full screen.

Attachments
Screenshot 2024-02-14 095443.png
Screenshot 2024-02-14 095443.png (22.24 KiB) Viewed 88 times

Post by ghulam.ghous »

Hi Thomasb,

I am unable to reproduce this issue in our online demos. Are you able to repro it in our demos? We have angular demos available here: https://bryntum.com/products/grid/examples/. Can you provide us with a small runnable test case so we can reproduce this issue on our end and investigate it?

Regards,
Ghous


Post by thomasb »

I make some customization to it as I need it to open when user click to select and for full screen also I don't use built in function of bryntum I changing container and append bryntum container to body.

Also I used one component to render data from clients or tags.

As below I will post my code .


<form class="d-flex">
    <mat-form-field [style.opacity]="_disabled ? 0.5: 1" color="primary">
        <mat-label>
            <mat-icon>search</mat-icon>
            {{ _ItemType === 'Client' ? ('CHOOSE_CLIENTS' | translate) : ('CHOOSE_TAGS' | translate) }}
        </mat-label>
        <mat-select-trigger [class.mt-20]="selectedData.length > 0 ">
            <mat-chip *ngFor="let item of selectedData.slice(0,sliceItemsLength)" [style.background-color]="item.color"
                [disabled]="_disabled" [style.color]="item.color | calculateOppositeColor">
                <i *ngIf="item.icon" class="fa fa-{{item.icon}} m-r-15"></i>
                {{item.name}}
                <mat-icon [style.color]="item.color | calculateOppositeColor" matChipRemove
                    (click)="markAsUnselected(item.id)">
                    cancel
                </mat-icon>
            </mat-chip>
            <span *ngIf="remainingItemsCount > 0">
                +{{remainingItemsCount}}
            </span>
        </mat-select-trigger>
        <mat-select [formControl]="itemCtrl">
            <mat-option hidden></mat-option>
            <div #table></div>
        </mat-select>
    </mat-form-field>
</form>

<div class="d-flex" #tableContainer>
    <bryntum-grid #grid [config]="gridConfig" [data]="_ItemType === 'Client' ?  gridConfig.data : gridTagConfig.data"
        (onSelectionChange)="onSelect($event)"></bryntum-grid>
    <button mat-icon-button (click)="toggleFullScreen()">
        <mat-icon *ngIf="!isFullScreen">fullscreen</mat-icon>
        <mat-icon *ngIf="isFullScreen">fullscreen_exit</mat-icon>
    </button>
</div>


import { Component, ElementRef, EventEmitter, Input, Output, ViewChild, inject } from '@angular/core';
import { UntypedFormControl } from '@angular/forms';
import { Grid, GridConfig, LocaleManager } from '@bryntum/grid';
import { BryntumGridComponent } from '@bryntum/grid-angular';
import { Subscription } from 'rxjs';
import { ClientsService } from 'src/app/shared/services/clients.service';
import { gridConfig } from './config';
import { TagsService } from 'src/app/shared/services/tags.service';
import * as _ from 'lodash';
import { TranslateService } from '@ngx-translate/core';

@Component({
  selector: 'bryntum-table',
  templateUrl: './bryntum-table.component.html',
  styleUrls: ['./bryntum-table.component.scss']
})

export class BryntumTableComponent {
  @ViewChild('tableContainer', { static: true }) tableContainer!: ElementRef;
  @ViewChild('table', { static: true }) table!: ElementRef;
  @ViewChild(BryntumGridComponent, { static : false }) gridComponent: BryntumGridComponent;
  @Output() ListChanged = new EventEmitter<object>();
  itemCtrl = new UntypedFormControl();
  private grid : Grid;
  selectedData: any[] = [];
  gridConfig: Partial<GridConfig> = _.cloneDeep(gridConfig);
  gridTagConfig: Partial<GridConfig> = _.cloneDeep(gridConfig);
  isFullScreen: boolean = false;
  private subscription: Subscription = new Subscription();
  private readonly clientsService = inject(ClientsService);
  private readonly tagsService = inject(TagsService);
  private readonly translateService = inject(TranslateService);
  sliceItemsLength : number = 7;
  remainingItemsCount: number;
  _disabled: boolean;
  _ItemType: string;
  @Input() set selectedItems(selectedData: any[]) {
    if(selectedData.length > 0 && selectedData.length !== this.selectedData.length) this.markAsSelected(selectedData)
  }
  @Input() set disabled(disabled : boolean){
    this._disabled = disabled;
    disabled  ? this.itemCtrl.disable() : this.itemCtrl.enable() ;
  };

  @Input() set ItemsType(type:string){
    this._ItemType = type;
    type === 'Client' ? this.loadClients() : this.loadTags();
  }


  onSelect = (event) => {
    const newSelection = event.selected.map((record) => record.data);
    const removedSelection = event.deselected.map((record) => record.data);
    this.selectedData = [
      ...this.selectedData.filter(item => !removedSelection.find(removed => removed.id === item.id)),
      ...newSelection.filter(item => !this.selectedData.find(selected => selected.id === item.id))
    ];
    this.calculateRemainingItems();  
this.ListChanged.emit(this.selectedData); } ngAfterViewInit(){ this.grid = this.gridComponent.instance; const container = this.tableContainer.nativeElement; container.style.height = '450px'; this.table.nativeElement.appendChild(container) this.setLanguage(); } toggleFullScreen() { const container = this.tableContainer.nativeElement; if (this.isFullScreen) { container.style.position = ''; container.style.top = ''; container.style.left = ''; container.style.width = ''; container.style.height = ''; container.style.backgroundColor = ''; container.style.zIndex = ''; container.style.height = '450px'; document.body.style.overflow = 'auto' this.table.nativeElement.appendChild(container) } else { container.style.position = 'fixed'; container.style.top = '0'; container.style.left = '0'; container.style.width = '100%'; container.style.height = '100%'; container.style.backgroundColor = '#fff'; container.style.zIndex = 999; document.body.style.overflow = 'hidden' document.body.appendChild(container) } this.isFullScreen = !this.isFullScreen; } setLanguage(){ if (this.translateService.currentLang) { LocaleManager.applyLocale(_.capitalize(this.translateService.currentLang)); } this.subscription.add( this.translateService.onLangChange .subscribe({ next: (language) => { const localeString = language.lang; LocaleManager.applyLocale(_.capitalize(localeString)); } }) ); } markAsUnselected(id:number){ this.grid.deselectRow(id);
this.grid.refreshRows(); } markAsSelected(selectedData){ console.log("selectedData",selectedData) const ids = selectedData.map(item=>item['id']); this.grid.selectedRecords = ids; this.grid.refreshRows(); } calculateRemainingItems() { this.remainingItemsCount = Math.max(0, this.selectedData.length - this.sliceItemsLength); } loadClients() { this.subscription.add( this.clientsService .getAllClients([], {}, {}, false, undefined, undefined, ['id', 'name', 'color']) .subscribe((allClients) => { this.gridConfig.data = allClients.result; }) ); } loadTags() { this.subscription.add( this.tagsService .getAllTags() .subscribe((allTags) => { this.gridTagConfig.data = allTags.result; }) ); } }

Post by ghulam.ghous »

Please post full code and data we could use to reproduce the issue. Best of all if you'll apply required changes to one of our demos and share a runnable code.


Post Reply