ng2-table icon indicating copy to clipboard operation
ng2-table copied to clipboard

Dynamic columns issue

Open petarblazevski opened this issue 9 years ago • 18 comments

Hi guys,

I've been trying to dynamically change the columns and the rows on a table. When i create the new array of columns, instead of re-creating the table with the new columns, the table is persisting the old columns, and appending the new once.

We found out that the "issue" is located in ng-table.component.ts starting from line 37.

Can you please give me an info if this is an issue, or if it was intentional made it like this? And if this is not an issue, is there a workaround?

petarblazevski avatar May 31 '16 11:05 petarblazevski

@petarblazevski how do you manage to re-create the table anyway onChanges? I need to update the data within my table and for some reason it is just not working...

//shortened
@Component({
    selector: 'section.news-letter-articles',
    template: `

                    Sortable table:
                    <ng-table [config]="config.sorting"
                               (tableChanged)="onChangeTable(config)"
                               [rows]="rows" [columns]="columns">
                    </ng-table>
                </div>   
              `,
    directives: [NG_TABLE_DIRECTIVES]
})

export class NewsLetterArticles {

    /**
     * @description onChange in tree of components (filter) getNewsLetter with new selected newsletterID
     * @method public
     * @return function with parameters
     * */
    ngOnChanges() {
        this.getNewsLetter(this.newsletterID, this.editionID);
    }
    /**
     * @description getNewsLetter data
     * @method private
     * @param newsletterID <string> id of Newsletter to fetch
     * @param editionID <string> if of Edition to fetch
     * @return function with parameter
     * */
    private getNewsLetter(newsletterID, editionID) {
var url = working
        this._newsLetterService.getNewsLetter(url)
            .subscribe(
                newsletter => this.newsletter = newsletter,
                error =>  this.errorMessage = <any>error,
                () => this.createArticleData(this.newsletter)
            );
    }

    //Table input

    TableData: Array<any> = [
        {
            'name': 'Victoria Cantrell',
            'position': 'Integer Corporation',
            'office': 'Croatia',
            'ext': '0839',
            'startDate': '2015/08/19',
            'salary': 208.178
        }];

    public rows:Array<any> = [];
    public columns:Array<any> = [
        {title: 'Name', name: 'name', sort:'asc'},
        {title: 'Position', name: 'position', sort: false},
        // {title: 'Office', name: 'office', sort: 'asc'},
        // {title: 'Extn.', name: 'ext', sort: ''},
        // {title: 'Start date', name: 'startDate'},
        // {title: 'Salary ($)', name: 'salary'}
    ];
    public page:number = 1;
    public itemsPerPage:number = 10;
    public maxSize:number = 5;
    public numPages:number = 1;
    public length:number = 0;

    public config:any = {
        paging: false,
        sorting: {columns: this.columns},
        filtering: {filterString: '', columnName: 'position'}
    };
    private createArticleData(newsletter){
        if(newsletter.length > 0 && newsletter[0].articles.length > 0){
            this.rows = newsletter[0].articles;
            this.length = this.data.length;
            this.onChangeTable(this.config);
        } else {
            console.log("no articles");
        }
    }
    private articleData:Array<any> = [{
        'name': "No Article available",
        'position': ''
    }];
    private data:Array<any> = this.articleData;


    public ngOnInit() {
        this.onChangeTable(this.config);
    }

    public changePage(page:any, data:Array<any> = this.data):Array<any> {
        console.log(page);
        let start = (page.page - 1) * page.itemsPerPage;
        let end = page.itemsPerPage > -1 ? (start + page.itemsPerPage) : data.length;
        return data.slice(start, end);
    }

    public changeSort(data:any, config:any):any {
        if (!config.sorting) {
            return data;
        }

        let columns = this.config.sorting.columns || [];
        let columnName:string = void 0;
        let sort:string = void 0;

        for (let i = 0; i < columns.length; i++) {
            if (columns[i].sort !== '') {
                columnName = columns[i].name;
                sort = columns[i].sort;
            }
        }

        if (!columnName) {
            return data;
        }

        // simple sorting
        return data.sort((previous:any, current:any) => {
            if (previous[columnName] > current[columnName]) {
                return sort === 'desc' ? -1 : 1;
            } else if (previous[columnName] < current[columnName]) {
                return sort === 'asc' ? -1 : 1;
            }
            return 0;
        });
    }

    public changeFilter(data:any, config:any):any {
        if (!config.filtering) {
            return data;
        }

        let filteredData:Array<any> = data.filter((item:any) =>
            item[config.filtering.columnName].match(this.config.filtering.filterString));

        return filteredData;
    }

    public onChangeTable(config:any):any {
        if (config.filtering) {
            Object.assign(this.config.filtering, config.filtering);
        }
        if (config.sorting) {
            Object.assign(this.config.sorting, config.sorting);
        }
        let filteredData = this.changeFilter(this.data, this.config);
        let sortedData = this.changeSort(filteredData, this.config);
        this.length = sortedData.length;
    }


}

alfakappa avatar Jun 02 '16 19:06 alfakappa

@alfakappa not really re-creating the table. In my case, i have 3 "radio buttons". So when you switch between them, i am re-defining the columns property

petarblazevski avatar Jun 02 '16 20:06 petarblazevski

Ok I have a slightly different issue here.

when I update rows, I do get the new info in my table. However, when I'm trying to sort this, it gives me this error: TypeError: item[config.filtering.columnName].match is not a function

really no clue what to do.

alfakappa avatar Jun 02 '16 20:06 alfakappa

+1 @petarblazevski On this issue. I am trying to display a table that changes it's columns when a different report is selected. Can't seem to change the columns dynamically.

kidtronnix avatar Aug 25 '16 14:08 kidtronnix

+1 I have the same problem. Doesn't seem to be a way to clear the columns before setting new columns

HenricusL avatar Nov 28 '16 06:11 HenricusL

I have the same problem, I can't remove a column after it's set. Anyone found a workaround ?

SylTi avatar Jan 04 '17 01:01 SylTi

I solved it by updating the data parsed to the table on ngChanges on the above component. Then in the table component onChanges I made a "createData function" and init the table again. It maybe a bit "bloathing" but works fine for me.

alfakappa avatar Jan 04 '17 06:01 alfakappa

when ever you made a change to columns then make sure you have call this function given below.

this.onChangeTable(this.config);

Hasnain-Bukhari avatar Jan 17 '17 07:01 Hasnain-Bukhari

@alfakappa could you please show a code example ? Trying to do something similar but so far no luck :

if (quaterly) { if (this.columns.find((col) => col.name === 'quaterly')) { console.log('splice'); this.columns.splice(10, 1); } } this.config = { sorting: {columns: this.columns}, className: ['table-striped', 'table-bordered', 'text-xs-center'] }; this.onChangeTable(this.config);

The splice get called successfully but the columns don't update

SylTi avatar Jan 23 '17 00:01 SylTi

Hmm.. that is weird actually.. I have it this way

ngOnChanges():void {
        this.createData(this.articles);
        this.onChangeTable(this.config);
    }

private createData(articles:Array<any>){
        let articlesArray:any = articles;

        if (articlesArray) {

            if(articlesArray.length > 0) {
                this.rows = articlesArray;
                this.tableData = articlesArray;

            } else {
                let firstCellValue = 'No articles',
                    firstCellName = 'Titel',
                    emptyMessage:any = {};
                emptyMessage[firstCellName] = firstCellValue;
                this.rows = [emptyMessage]
            }
        }
    }

I think the table will only update itself if you update this.rows and this.data (original code, I renamed it to tableData)

So I think you might need to update dat within your if(quaterly)-statement as well. Make a new array of rows and then update this.rows if that makes sense to you.

alfakappa avatar Jan 23 '17 07:01 alfakappa

I'm not sure that's the problem since i'm already updating this.rows inside of the onChangeTable :

public onChangeTable(config:any):any {
    if (config.sorting) {
      Object.assign(this.config.sorting, config.sorting);
    }
    this.opportunitiesService.getList()
      .subscribe(
        (data) => {

          this.rows = data;
});

SylTi avatar Jan 30 '17 02:01 SylTi

does anyone figured it out. how to dynamically change colums

ervbsankar avatar Feb 07 '17 21:02 ervbsankar

I have changed locally ng-table.component.ts (I'm using sinopia so i can easily handle local adjustments).

just added this method: public clearColumns () : void { this._columns = []; }

I've also created a pull request.

HenricusL avatar Feb 08 '17 06:02 HenricusL

+1

Is this pull request merged? If not can you link to it please and/or give us a status? Thanks.

shamgang avatar Feb 27 '17 18:02 shamgang

Sorry for the slow reaction. https://github.com/valor-software/ng2-table/pull/433

HenricusL avatar Mar 20 '17 13:03 HenricusL

Hi How would I call this method clearColumns() from the parent component? Also, isn't it better to clear the columns array when the property setter gets called?

RamiAtieyeh avatar Mar 16 '18 10:03 RamiAtieyeh

@RamiAtieyeh Not sure what you mean. I call this method when I want to replace the dataset completely. I agree this would be better to call in the setter.. but that really would cahnge the setter functionality and possibly break something.

HenricusL avatar Mar 16 '18 10:03 HenricusL

Hello everyone,

I chose to fix the problem directly in the setter by refreshing all columns as you can see:

@Input()
  public set columns(values:Array<any>) {
    // Column reset added, now we always repopulate de columns instead of recycling, preventing columns refresh bugs
    this._columns = [];
    values.forEach((value:any) => {
      if (value.filtering) {
        this.showFilterRow = true;
      }
      if (value.className && value.className instanceof Array) {
        value.className = value.className.join(' ');
      }

      this._columns.push(value);
    });
  }

And here the component part with the configuration refresh:


//Add LocalIT column for SHOW ALL mode
        this.columns = [
          {title: 'Local IT', name: 'LocalIT', filtering: {filterString: '', placeholder: 'LocalIT'}, sort:'', className: 'groupidColumnWidth'},    
          {title: 'Product Name', name: 'ProductName', filtering: {filterString: '', placeholder: 'Product Filter'}, sort:'', className: 'productColumnWidth'},    
          {title: 'Target', name: 'Target', filtering: {filterString: '', placeholder: 'GID Filter'}, sort: '', className: 'groupidColumnWidth'},    
          {title: 'Status', name: 'Status', filtering: {filterString: '', placeholder: 'Status Filter'}, sort: '', className: 'statusColumnWidth'},    
          {title: 'Creation Date', name: 'CreatedOn', sort: '', className: 'dateColumnWidth'},
          {title: 'Modification Date', name: 'ModifiedOn', sort:'', className: 'dateColumnWidth'},
          {title: 'Requestor', name: 'Requestor', filtering: {filterString: '', placeholder: 'GID Filter'}, sort:'', className: 'groupidColumnWidth'}
        ];

        //Refresh the sorting onfiguration with the ne column and update de table with the new config
        if(this.config){
          this.config.sorting = {columns: this.columns};
        }

        this.onChangeTable(this.config);

For now i've no downside with this fix. I hope it can help someone,

Have a nice day

itsnotme01 avatar Jun 29 '18 12:06 itsnotme01