I'm working on a project that requires a table to be dynamically constructed from an array of header objects:
[{ field: "name", show: true, title: "Name"},
{ field: "id", show: true, title: "ID"},
{ field: "time", show: true, title: "Time"}]
and an array of data objects that is updated at an interval:
[{ name: "Abc", id: 123, time: "300" },
{ name: "Def", id: 456, time: "10" }]
My template looks something like this:
<table class="table">
<thead>
<th ng-repeat="header in cols">
{{::header.title}}
</th>
</thead>
<tbody>
<tr ng-repeat="row in visibleData">
<td ng-repeat="col in cols">
{{::row[col.field]}}
</td>
</tr>
</tbody>
</table>
Please note that this is a simplified version but it holds the important bits.
As of now, rendering a table with 10 cols and 20 rows takes around 200ms (which creates a noticeable lag in scrolling and other page animations).
As you can see, I've tried to use one-time biding but that hasn't improved the performance noticeably.
Another thing I've tried was to 'track by' row.id, but this caused the data to stop updating altogether (The initial DOM object is reused even though some columns have changed).
So my question is, what measures should I take in order to optimize this configuration?
Any help would be greatly appreciated.
Thanks :)
Related
I have a pretty simple datatables object. I bind it to an array of objects, specify the data fields and it works. The problem is when I try to implement the CSV export. It always only wants to export the first row of the table. Any ideas?
Here's where my code stands at the moment. And to be sure, I've made sure that the button and select libraries are included but that has made no difference.
<table id="tblData" style="display:none;">
<thead>
<tr id="trDataTableHeader">
<th data-s-type="string">Name</th>
<th data-s-type="string">Address</th>
<th data-s-type="string">Phone</th>
<th data-s-type="string">Website</th>
<th data-s-type="string">Types</th>
</tr>
</thead>
</table>
...
table = $('#tblData').DataTable({
dom: 'rtB',
data: tableData,
columns: [
{ "data": "name" },
{ "data": "address" },
{
"data": "phone_number",
defaultContent: ""
},
{
"data": "website",
defaultContent: ""
},
{
"data": "types",
defaultContent: ""
},
],
buttons: [{
extend: "csv",
text: "Export",
exportOptions: {
modifier: { search: "none", selected: false}
}
}],
select: false,
lengthChange: false,
sort: false,
paging: false
});
After a lot of digging, I made an accidental discovery when I removed the column data type specifications. I got an error message that str.replace is not a function.
Turns out that the parseInt and parseFloat base functions were being overridden by another developer on that page and was causing a problem but DataTables was too graceful to tell me.
This is why you don't override base javascript functions unless you absolutely have to.
I don't have any experience in Knockout js but since I have to implement the functionality and struggling to get my hands on this scenario.
JSP files are fetching JSON data and it is passed to HTML template to create dynamic table.But i have to match particular values and give different styling to cells(Need to change color).
I explored and found out if Foreach is used and using if condition to apply css class can work but since table is getting created dynamically so finding it difficult to achieve it.
Providing the code below,i know angular way to do it but since its in knockout JS am struggling.
The above JSON data fetching dynamically from DB, if App Server is responding then map to “Yes” otherwise map to “No”, in additionally I have to set Yes mean green color, No means Red color.
I mapped responding values, it is working fine.
But I am not able to set colors for responding values (Yes means green and No means red color) in Knockout js. Can you please suggest me on this
<table id="monitorTable" summary="Table Data Test" aria-label="Table Data Test"
contextmenu="empty"
data-bind="ojComponent: {component: 'ojTable',
data: testdatasource,
columnsDefault: {sortable: 'disabled'},
columns: tableColumns,
scrollPolicy: scrollPolicy,
scrollPolicyOptions: scrollPolicyOptions}"></table>
Below here is the JSOn data fetched from server and passed to table
{
"label": "App Server",
"collection": [{
"responding": "Yes",
"appserver": "DEFAULT",
"className": "success",
"id": 1
}, {
"responding": "No",
"appserver": "ORACLEQUEUE",
"className": "failed",
"id": 2
}, {
"responding": "No",
"appserver": "SECONDARY",
"className": "failed",
"id": 3
}, {
"responding": "No",
"appserver": "TERTIARY",
"className": "failed",
"id": 4
}],
"serverTimestamp": "2017-07-07T03:51:21.949+0000",
"dataTimestamp": "2017-07-07T03:51:21.949+0000",
"tableColumns": [{
"headerText": "App Server",
"field": "appserver",
"sortable": "disabled"
}, {
"headerText": "Responding",
"field": "responding",
"sortable": "disabled",
"className": ""
}],
"scrollPolicy": "auto",
"scrollPolicyOptions": {
"fetchSize": "15",
"maxCount": "1000"
}
}
Here is the code which fetches data from server by JSP files
function addScalabilityMonitors() {
console.log("moved to scalability");
//App Scalability
monitors.addMonitorPoint(sts.apiBaseUrl() + 'ScalabilityAppServer1.jsp', 'oj-masonrylayout-tile-3x2', true, 15000, 'grid', 'scalability');
//Web Scalability
monitors.addMonitorPoint(sts.apiBaseUrl() + 'ScalabilityWebServer1.jsp', 'oj-masonrylayout-tile-3x2', true, 15000, 'grid', 'scalability');
//Response Time
monitors.addMonitorPoint(sts.apiBaseUrl() + 'Scalability.json', 'oj-masonrylayout-tile-3x2', true, 15000, 'gauge', 'scalability');
//Log files
monitors.addMonitorPoint(sts.apiBaseUrl() + 'logfile.json', 'oj-masonrylayout-tile-3x2', true, 15000, 'grid', 'scalability');
monitors.addMonitorPoint(sts.apiBaseUrl() + 'ProcessSchedules.json', 'oj-masonrylayout-tile-3x2', true, 15000, 'grid', 'scalability');
monitors.addMonitorPoint(sts.apiBaseUrl() + 'BusinessSequence.json', 'oj-masonrylayout-tile-3x2', true, 15000, 'grid', 'scalability');
monitors.addMonitorPoint(sts.apiBaseUrl() + 'DatabaseJobs.json', 'oj-masonrylayout-tile-3x2', true, 15000, 'grid', 'scalability');
//myPostProcessingLogic();
}
I tried to read the documentation for this, also tried various things but failed to implement.
Assuming you have access to the css this is pretty simple. If not, it's only slightly simple. Knockout has a databinding specifically for css. Here's an example.
function Server(data) {
var self = this;
self.Name = ko.observable(data.Name);
self.Status = ko.observable(data.Status);
}
function viewModel() {
var self = this;
self.Servers = ko.observableArray();
self.Load = function() {
self.Servers.push(new Server({
Name: "Email",
Status: "Online"
}));
self.Servers.push(new Server({
Name: "TPS Reports",
Status: "Offline"
}));
};
self.Load();
}
ko.applyBindings(new viewModel());
.red {
background-color: red;
}
.blue {
background-color: blue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<h3> CSS Control</h3>
<table border=1>
<thead>
<tr>
<th> Server Name</th>
<th> Server Status</th>
</tr>
</thead>
<tbody data-bind="foreach: Servers">
<tr>
<td> <span data-bind="text: Name"> </span> </td>
<td data-bind="css: { red: Status() == 'Offline', blue: Status() == 'Online' } "> <span data-bind="text: Status"> </span> </td>
</tr>
</tbody>
</table>
<br><br><br><br>
<h3> No CSS Control</h3>
<table border=1>
<thead>
<tr>
<th> Server Name</th>
<th> Server Status</th>
</tr>
</thead>
<tbody data-bind="foreach: Servers">
<tr>
<td> <span data-bind="text: Name"> </span> </td>
<!-- Note: anything with a hyphen must be surrounded in single quotes -->
<td data-bind="style: { 'background-color': Status() == 'Online' ? 'green' : 'black' } "> <span data-bind="text: Status"> </span> </td>
</tr>
</tbody>
</table>
With your code, you would just make some additions to the data-binding in question.
I am working on a project with KnockoutJS where we are pulling data in via Ajax calls and storing them in ko.observableArray. Currently, I have the following table in HTML:
`<table id="gpa">
<tbody data-bind="foreach: gpa">
<tr>
<td data-bind="text: LEVEL"></td>
<td data-bind="text: GPA_TYPE"></td>
<td data-bind="text: HOURS_ATTEMPTED"></td>
<td data-bind="text: HOURS_EARNED"></td>
<td data-bind="text: GPA"></td>
</tr>
</tbody>
</table>`
The JavaScript we have for generating the content via DataTables and the associated options is:
var gpaTarget = {
tableId: 'gpa',
options: {
paging: false,
ordering: false,
info: false,
searching: false,
processing: true,
autoWidth: true
},
columns: [
{ title: 'Level', data: 'LEVEL' },
{ title: 'GPA Type', data: 'GPA_TYPE' },
{ title: 'Hours Attempted', data: 'HOURS_ATTEMPTED' },
{ title: 'Hours Earned', data: 'HOURS_EARNED' },
{ title: 'GPA', data: 'GPA' },
]
}
//Add the DT target for Gpa data
dataTableTargets.push(gpaTarget);
//Initialize datatables for the appropriate DOM elements
if (dataTableTargets.length !== 0) {
$(document).ready(function () {
dataTableTargets.forEach(function (target) {
var table = target.tableId;
var options = target.options;
$('#' + table).DataTable(options);
});
Ideally, the idea from the DataTables.net site's description of how the Column.title feature works is that with a <thead> section, the title property for each column should render a simple column header (see https://datatables.net/reference/option/columns.title for reference.)
However, I have no column headers unless I explicitly declare them in my HTML. As their page says the <thead> element could be non-existent, or that the columns.title option can override the existing <thead> content, I am at a loss for why this is not working as expected.
Does anyone have any insight into what I might be doing incorrectly for this scenario? Any guidance is greatly appreciated.
I am trying to initialize data tables and feed it an array of objects. I am getting an error saying that there is No data available in table. But I can print it out to the console and see that that is incorrect.
//JS
get_notes().done(funciton(){
console.log(my_json)//what its format is below
//my_json = [
{
"username": "thomas",
"fullname": "Thomas familyname"
},
/*...*/]
_.isArray(my_json) //true
$("#note_table").DataTable({
data: my_json,
columns: [
{title: "fullname"},
{title: "username"}
]
});
});
<!--HTML-->
<table id="note_table">
<thead>
<tr>
<th>fullname</th>
<th>username</th>
</thead>
<tobdy>
</tbody>
</table>
How can I prevent this error?
Your biggest problem is this:
columns: [
{title: "fullname"},
{title: "username"}
]
it should be
columns: [
{data: "fullname"},
{data: "username"}
]
You also have to make sure your table is properly defined (typo <tobdy>)
Here's a link to a working fiddle for your example:
http://jsfiddle.net/bmartinelle/bjppck3d/1/
I have a javascript object that I want to bind to a table using KnockoutJS
Here's my object:
var data = {
"Warnings": {
"numbers": 30,
"content": [
{
"number" : 3001,
"description" : "There may be a problem with the device you are using if you use the default profile"
},
{
"number" : 3002,
"description" : "There may be a problem with the device you are using if you don't use the default profile"
}
]
},
"Errors": {
"numbers": 20,
"content": [
{
"number": 1000,
"description": "No network is loaded"
},
{
"number": 1000,
"description": "No network is loaded"
}
]
}
};
ko.applyBindings(data);
Here's my html code:
<table class="table table-hover">
<thead>
<tr>
<th style="width:100px">Numero</th>
<th>Description</th>
</tr>
</thead>
<tbody data-bind="foreach: Warnings.content">
<tr data-bind="foreach: $data">
<td data-bind="text: $data.number"></td>
<td data-bind="text: $data.description"></td>
</tr>
</tbody>
</table>
Here's a JSFiddle: http://jsfiddle.net/etiennenoel/KmKEB/
I really need to use this format for my data Object.
I don't know why I'm not having the Warnings listed in a table since I'm not getting any errors...
You have an extra foreach that is not needed. Simply remove the foreach on your tr. The foreach on your tbody will assign a new value for $data for each tr that is rendered in the loop.