Generate table body rows using ng-repeat - javascript

I'm using Smart Table (latest version) and AngularJs (v. 1.2.16) to build a table using two objects, one for the header and the other for the table content. My problem happens when creating the table body cells. Using the following code works fine:
<tr ng-repeat="row in rowCollection">
<td>{{row.productNumber}}</td>
<td>{{row.BuyIt}}</td>
<td>{{row.brand}}</td>
</tr>
But I need to generate the body like this:
<tr ng-repeat="row in rowCollection">
<td ng-repeat="col in columns">{{value-to-show}}</td>
</tr>
My object is this:
$scope.rowCollection = [{
"productNumber": 5877,
"BuyIt": "Online",
"brand": "BrandA"
}, {
"productNumber": 5743,
"BuyIt": "Online",
"brand": "BrandB"
}];
$scope.columns = [{
'colName': 'Product Number',
'Id': 'column1',
'className': '',
'skipNatural': true,
'sortDefault': 'reverse'
}, {
'colName': 'Store or Online',
'Id': 'column2',
'className': '',
'skipNatural': true
}, {
'colName': 'Brand',
'Id': 'column3',
'className': '',
'skipNatural': true
}];
How can I get the right value to appear in the right cell?
I have a jsfiddle that shows the problem: http://plnkr.co/edit/aEfzzU?p=preview
Any help is really appreciated.

You can change your ng-repeat to this:
<tbody>
<tr ng-repeat="row in rowCollection">
<td ng-repeat="(key, value) in row">{{value}}</td>
</tr>
</tbody>

You may also extend your column objects with which property it corresponds with like this:
<tr ng-repeat="row in rowCollection">
<td ng-repeat="col in columns">{{row[col.property]}}</td>
</tr>
This will also have the nice side effects of:
You may in your header use the st-sort directive on col.property to enable sorting
Dynamically change which columns to display
Use your column objects as a configuration for both header and body
Use on complex objects which contains more properties than you care to show!

Related

How can I extend a table with backend data by columns instead of rows in Vue.js?

I have a table layout that currently looks like this:
This works well because I can place all my data for one row inside of my item object, and just render the TableRow object as <tr><td>...</td><td>...</td>....
One solution could be to subdivide my item object by column, and return only the corresponding value:
<tbody>
<tr v-for="(item, rowIndex) in store.selectedItems" :key="item.id">
<!-- iterate over each column within each row -->
<td v-for="(col, colIndex) in columns" :key="colIndex">
{{ item[col.field] }}
</td>
</tr>
</tbody>
However, ideally I would like to define the whole column in a single TableCol component instead of having to render the entire table like this. Is this somehow possible?
As per my understanding you want to create a separate shared component for column, So that you can reuse that anywhere by just passing a dynamic props. If Yes, Here you go :
Vue.component('tableCol', {
props: ['column', 'rowitem'],
template: `<td>{{ rowitem[column.field] }}</td>`
});
var app = new Vue({
el: '#app',
data: {
store: {
selectedItems: [{
id: 1,
name: 'Alpha',
age: 21
}, {
id: 2,
name: 'Beta',
age: 25
}, {
id: 3,
name: 'Gamma',
age: 30
}]
},
columns: [{
field: 'name'
}, {
field: 'age'
}]
}
});
table, tr, td {
border: 1px solid black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<table>
<tbody>
<tr v-for="item in store.selectedItems" :key="item.id">
<template>
<table-col v-for="(column, index) in columns" :column="column" :rowitem="item" :key="index"/>
</template>
</tr>
</tbody>
</table>
</div>

Having problems with importing html tables to Tabulator

I have recently switched from Tabulator 4.5 to 5.0 and I am having some problems with my old code. I used to just give existing Drupal HTML tables a Tabulator skin, however, now while the tables are generated, the data is lost, and no rows are displayed. Here is an example:
HTML
<table data-drupal-selector="edit-cimek" class="responsive-enabled table table-hover table-striped" id="edit-cimek"
data-striping="1">
<thead>
<tr>
<th>Hivatalos név</th>
<th>Címtípus</th>
<th>Teljes cím</th>
<th>Kontakt</th>
<th>Gombok</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>AAAAAAAAAAAAAAAAAAAA</td>
<td>BBBBBBBBBB</td>
<td>CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC</td>
<td>DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD</td>
<td><a id='cimtorol_5' class='cimtorol'><img title='Törlés'
src='/src/here' alt='Törlés' width='30px'></a> <a
id='cimmodosit_5' class='cimmodosit'><img title='Módosítás'
src='/src/here' alt='Módosítás' width='30px'></a>
</td>
</tr>
<tr class="even">
<td>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA</td>
<td>BBBBBBBBB</td>
<td>CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC</td>
<td>D</td>
<td><a id='cimtorol_1' class='cimtorol'><img title='Törlés'
src='/src/here' alt='Törlés' width='30px'></a> <a
id='cimmodosit_1' class='cimmodosit'><img title='Módosítás'
src='/src/here' alt='Módosítás' width='30px'></a>
</td>
</tr>
</tbody>
</table>
JS
var table = new Tabulator("#edit-cimek", {
columns: [
{ title: Drupal.t('Official name'), field: "name", sorter: "string" },
{ title: Drupal.t('Address type'), field: "type", sorter: "number" },
{ title: Drupal.t('Full address'), field: "address", sorter: "string" },
{ title: Drupal.t('Contact'), field: "kapcstarto", sorter: "number" },
{
title: Drupal.t('Buttons'), field: "buttons", sorter: "string", formatter: "html", cellClick: function (e, cell) {
e.preventDefault();
}
}
]
});
What might be the problem, and why doesn't it work in 5.0 when it worked in 4.5?

How to check table column data type

I am trying to make table configurable. Before that I am making demo component through which I can make a my own configurable table.
I want to pass few things to my table like, column names and data.
Column Name I want to pass like this:
headers = [
{name: 'Sr.No'},
{name: 'name', dataType: 'text'},
{name: 'mobile', dataType: 'number'},
{name: 'date', dataType: 'date'},
{name: 'Action'}
];
the dataType above states that this column will have input type text when is editable, same for number and date as well.
I want to show input boxes based on this values, but in <td> I am not able to check this dataType key. I tried this:
html
<table class="row-border border-1 table">
<thead>
<tr>
<th *ngFor="let head of headers">{{head.name}}</th>
</tr>
</thead>
<tr *ngFor="let tableData of data; let i=index">
<td>{{i+1}}</td>
<ng-container *ngIf="tableData.isEditable; else viewable">
<div *ngIf="tableData.dataType ==='text'">
<input type="text">
</div>
<div *ngIf="tableData.dataType ==='date'">
<input type="date" >
</div>
<div *ngIf="tableData.dataType ==='number'">
<input type="date">
</div>
</ng-container>
<td>
<button *ngIf="!tableData.isEditable" (click)="onEdit(tableData)">Edit</button>
<button *ngIf="!tableData.isEditable">Delete</button>
<button *ngIf="tableData.isEditable" (click)="onSave(tableData)">Update</button>
</td>
<ng-template #viewable>
<td>{{tableData.name}}</td>
<td>{{tableData.mobile}}</td>
<td>{{tableData.date}}</td>
</ng-template>
</tr>
</table>
ts file
headers = [
{name: 'Sr.No'},
{name: 'name', dataType: 'text'},
{name: 'mobile', dataType: 'number'},
{name: 'date', dataType: 'date'},
{name: 'Action'}
];
data = [
{id:1, name: 'sam', mobile: '8788888888', date: '20/11/2021', isEditable: false},
{id:2, name: 'joy', mobile: '9788888888', date: '22/11/2021', isEditable: false},
]
onEdit(data) {
this.data.map((item) => {
item.isEditable = data.id === item.id;
})
}
onSave(data) {
data.isEditable = false;
}
Is there any way, so that I can check the column dataType and based on that I am able to show that input box in that cell of row when I click on edit button? Thanks in advance!!!
Oh dear lord have I spent much time in my past to create beautiful and editable tables.
I know how annoying this can be so I took my time and looked at your example.
Here is a quick and very dirty version I took your example.
You need to be able to map the headers to the properties of the data otherwise you can't identify which column represents which values as it is currently hardcoded in your example.
headers = [
{name: 'Sr.No'},
{name: 'name', dataType: 'text', mappedProperty: 'name'},
{name: 'mobile', dataType: 'number', mappedProperty: 'mobile'},
{name: 'date', dataType: 'date', mappedProperty: 'date'},
{name: 'Action'}];
Furthermore you need to iterate through the headers in the view template to get the mappedProperty and to figure out which dataType it has.
Here is the possible solution:
<table class="row-border border-1 table">
<thead>
<tr>
<th *ngFor="let head of headers">{{head.name}}</th>
</tr>
</thead>
<tr *ngFor="let tableData of data; let i=index">
<td>{{i + 1}}</td>
<ng-container *ngIf="tableData.isEditable; else viewable">
<ng-container *ngFor="let head of headers">
<ng-container *ngIf="head.mappedProperty">
<td>
<input [type]="head.dataType" [(ngModel)]="tableData[head.mappedProperty]">
</td>
</ng-container>
</ng-container>
</ng-container>
<td>
<button *ngIf="!tableData.isEditable" (click)="onEdit(tableData)">Edit</button>
<button *ngIf="!tableData.isEditable">Delete</button>
<button *ngIf="tableData.isEditable" (click)="onSave(tableData)">Update</button>
</td>
<ng-template #viewable>
<td>{{tableData.name}}</td>
<td>{{tableData.mobile}}</td>
<td>{{tableData.date}}</td>
</ng-template>
</tr>
</table>
And here is the onEdit function. In my opinion you just need to toggle isEditable. But I am unsure what you were trying in the example so sorry for any misunderstand:
onEdit(tableData: any) {
tableData.isEditable = !tableData.isEditable;
}
Have fun with the example and if you need any help let me know.
Here is the running example:
Important: This is way to much to write for each table.
Do yourself a favore and abstract it into a component and reuse it. Some interface like this should work. And the code is quite similar to the current.
<my-table-component [columnDefinition]="headers" [rows]="data"></my-table-component>

Space between data when exporting excel file from datatables

I have this bug on my export file using Datatables. There are some unnecessary space between the data.
<script>
$(document).ready(function () {
$('.dataTablesWExport').DataTable({
dom: 'Bfrtip',
buttons: [{
extend: 'excelHtml5',
exportOptions: {
columns: ':visible'
}
},
{
extend: 'pdfHtml5',
exportOptions: {
columns: ':visible'
}
},
'colvis'
],
"order": []
});
});
</script>
Screeshot of the export file
https://i.stack.imgur.com/X4gah.png
You can use a row function to control which rows are exported (the rows with data) and which are not (the blank rows).
Example
Assume I have the following data in my table:
<table id="myTable" class="display nowrap dataTable cell-border" style="width:100%">
<thead>
<tr>
<th>Name</th>
<th>Position</th>
<th>Office</th>
</tr>
</thead>
<tbody>
<tr>
<td>Adélaïde Fleury</td>
<td>System Architect</td>
<td>Paris</td>
</tr>
<tr>
<td>John Smith</td>
<td>Accountant</td>
<td>London</td>
</tr>
<tr>
<td></td>
<td></td>
<td>Tokyo</td>
</tr>
</tbody>
</table>
My DataTable object is defined like this:
$('#myTable').DataTable( {
dom: 'Bfrtip',
buttons: [
{
extend: 'excel',
exportOptions: {
columns: [ 0, 1 ], // just for my demo
rows: function ( idx, data, node ) {
return data[0];
}
}
}
]
} );
This is displayed as follows:
It uses a rows function to test each row. If the first cell in the row (data[0]) has data in it, then the row will be exported to Excel. But if the cell is blank, empty, or null, the row will not be exported:
How It Works
The row function returns a value of true or false for each row in the DataTable. JavaScript will therefore treat a non-blank value in data[0] as truthy - and therefore that row is returned.
So, return data[0] is just a more compact way of writing this:
if ( data[0].length > 0 ) {
return true;
} else {
return false;
}
Data Arrays vs Data Objects
My source data was taken directly from the HTML table, so it was provided as arrays of data (one array for each row): [ 'John Smith', 'Accountant' ]. This is why I used data[0] to check the contents of the first cell in each row.
If my data had been sourced from a JSON object, it may have looked different, for example:
{
"name": "John Smith",
"position": "Accountant"
},
{
...
}
In this case, data[0] would not work. I would need to use data.name instead.

table in Angular using dynamic table headers

I was creating an angular app to display data from various data sources. I configured the list of various data sources in a JSON file each data source has a set of values attached to it.
Here is an example
var configurableConfigurations=[
{
name:"Locations",
table:"location_set",
columnList:[
{
name:"LOCATION_NAME",
alias:"Location",
primary:true
},
{
name:"DESCRIPTION",
alias:"Description",
primary:false
}
]
},
{
name:"System Parameters",
table:"system_params",
columnList:[
{
name:"param_Key",
alias:"Parameter",
primary:true
},
{
name:"param_Value",
alias:"Value",
primary:false
}
]
}
];
I then created an HTML page to display this using angular : the page has 2 parts
1. A select box which shows various parameters this is done using ng-repeat
<select name="ConfigurationName" ng-model="selected" ng-options="eachConfiguration.name for eachConfiguration in configurableConfigurations" ng-change="fetchRequiredConfiguration()">
A table which I want to generate using the headers of the parameter selected
this is my code to do that
<table id="configtable">
<thead>
<tr>
<th class="col-md-1" ng-repeat="column in selected.columnList" >{{column.alias}}</th>
</tr>
</thead>
This works great for the first time. But when the option is selected again using the select box the table header is not shown.
The table data is being populated properly , its just the table headers that are getting messed up.
Could anyone please help me get around this problem. I am new to angularjs. May be I am missing something important.
Edit ::
I should Also Mention that I fetch the data from the API and then was using the Data table plugin(https://www.datatables.net/download/) to show this as Data
$("#configtable").DataTable({
"ajax": "../fetchvalue/config/"+this.selected.table,
destroy: true,
"columns":{ "data": "ColumnXXX"},
{"data": "ColumnYYY" }
});
As it turns out, I have a problem with the disappearing headers only when I use the DataTable
I don't know how the table data is store but this way is good:
$scope.configurableConfigurations = [{
name: "Locations",
table: "location_set",
columnList: [{
name: "LOCATION_NAME",
alias: "Location",
primary: true
}, {
name: "DESCRIPTION",
alias: "Description",
primary: false
}],
data:[[12,"home"],[43,"work"]]
}, {
name: "System Parameters",
table: "system_params",
columnList: [{
name: "param_Key",
alias: "Parameter",
primary: true
}, {
name: "param_Value",
alias: "Value",
primary: false
}],
data:[["GOO",586],["FOO",123]]
}];
And then you can print the table like this:
<select name="ConfigurationName" ng-model="selected" ng-options="eachConfiguration as eachConfiguration.name for eachConfiguration in configurableConfigurations" ng-change="fetchRequiredConfiguration()"></select>
<table id="configtable">
<thead>
<tr>
<th class="col-md-1" ng-repeat="column in selected.columnList">{{column.alias}}</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="row in selected.data" >
<td class="col-md-1" ng-repeat="col in row">{{col}}</td>
</tr>
</tbody>
</table>
Example here

Categories

Resources