Knockout table bindings with an object - javascript

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.

Related

Fill Datatable with Variable dont work. But if i put the exact same value to a php site and request it with ajax. It works.... Why?

This is in the variable "test":
{"data":[{"HistChar_ID":"4","Vorname":"Garnier","Nachname":"de
Naplouse"},{"HistChar_ID":"2","Vorname":"Robert","Nachname":"de
Sable"},{"HistChar_ID":"7","Vorname":"Ibn","Nachname":"Dschubair"},{"HistChar_ID":"6","Vorname":"Baha
ad-Din","Nachname":"ibn
Schaddad"},{"HistChar_ID":"1","Vorname":"Richard","Nachname":"L\u00f6wenherz"},{"HistChar_ID":"5","Vorname":"Wilhelm","Nachname":"von
Montferrat"}]}
HTML:
<table id="example" class="display" style="width:100%">
<thead class="thead1">
<tr>
<th class="th1">HistChar_ID</th>
<th class="th2">Vorname</th>
<th class="th3">Nachname</th>
</tr>
</thead>
<tfoot class="tfoot1">
<tr>
<th class="th1">HistChar_ID</th>
<th class="th2">Vorname</th>
<th class="th3">Nachname</th>
</tr>
</tfoot>
</table>
An the following Code Wont fill the Datatable.
$('#example').DataTable({
data: test,
columns: [
{ data: 'HistChar_ID' },
{ data: 'Vorname' },
{ data: 'Nachname' },
]
it throws an Error like this:
DataTables warning: table id=example - Requested unknown parameter
'HistChar_ID' for row 0, column 0. For more information about this
error, please see http://datatables.net/tn/4
I tried so much. But if i take whats inside of "test" and put it into a php and use ajax it works just fine with this.
$('#example').DataTable({
ajax: 'RESOURCES/PHP/Searchfield.php',
columns: [
{ data: 'HistChar_ID' },
{ data: 'Vorname' },
{ data: 'Nachname' },
]
PHP/Searchfield
include 'connection.php';
$searchstuff = $_GET['Searchfield'];
$sql = "select * FROM historischercharacter WHERE Vorname LIKE '%$searchstuff%' OR Nachname LIKE '%$searchstuff%' ORDER BY Nachname" ;
$result = mysqli_query($conn, $sql) or die("Error in Selecting " . mysqli_error($conn));
$emparray = array();
while($row =mysqli_fetch_assoc($result))
{
$emparray[] = $row;
}
echo json_encode(array('data'=>$emparray));
mysqli_close($conn);
Can someone explain me why? Is it impossible to fill the Datatable with a variable?? I just dont get it...
If you look at the examples in the documentation, the hard-coded array being passed into the table doesn't have the outer data property, it's just an array by itself - see https://datatables.net/examples/data_sources/js_array.html . You can see the same thing here as well: https://datatables.net/reference/option/data
The requirements when defining an AJAX data source are different. As per the example at https://datatables.net/reference/option/ajax by default you must supply an object with a "data" property as per the structure you've shown us in your question.
So it's simply that the requirements for each type of data source are different. Always read the documentation!
Demo of how to set the data source using a variable, with your variable. Note the absence of the "data" property...instead "test" is just a plain array:
var test = [{
"HistChar_ID": "4",
"Vorname": "Garnier",
"Nachname": "de Naplouse"
}, {
"HistChar_ID": "2",
"Vorname": "Robert",
"Nachname": "de Sable"
}, {
"HistChar_ID": "7",
"Vorname": "Ibn",
"Nachname": "Dschubair"
}, {
"HistChar_ID": "6",
"Vorname": "Baha ad-Din",
"Nachname": "ibn Schaddad"
}, {
"HistChar_ID": "1",
"Vorname": "Richard",
"Nachname": "L\u00f6wenherz"
}, {
"HistChar_ID": "5",
"Vorname": "Wilhelm",
"Nachname": "von Montferrat"
}];
$('#example').DataTable({
data: test,
columns: [{
data: 'HistChar_ID'
},
{
data: 'Vorname'
},
{
data: 'Nachname'
},
]
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.datatables.net/1.12.1/js/jquery.dataTables.min.js"></script>
<table id="example" class="display" style="width:100%">
<thead class="thead1">
<tr>
<th class="th1">HistChar_ID</th>
<th class="th2">Vorname</th>
<th class="th3">Nachname</th>
</tr>
</thead>
<tfoot class="tfoot1">
<tr>
<th class="th1">HistChar_ID</th>
<th class="th2">Vorname</th>
<th class="th3">Nachname</th>
</tr>
</tfoot>
</table>
Here is an example using a JavaScript variable which does not require you to change the data you show in your question:
var test = { "data": [ { ... }, { ... }, ... ] };
In the above structure, each element in the array [ ... ] contains the data for one table row.
In this case, the DataTable uses the data option to specify where that array can be found:
data: test.data
Here is the runnable demo:
var test = {
"data": [{
"HistChar_ID": "4",
"Vorname": "Garnier",
"Nachname": "de Naplouse"
}, {
"HistChar_ID": "2",
"Vorname": "Robert",
"Nachname": "de Sable"
}, {
"HistChar_ID": "7",
"Vorname": "Ibn",
"Nachname": "Dschubair"
}, {
"HistChar_ID": "6",
"Vorname": "Baha ad-Din",
"Nachname": "ibn Schaddad"
}, {
"HistChar_ID": "1",
"Vorname": "Richard",
"Nachname": "L\u00f6wenherz"
}, {
"HistChar_ID": "5",
"Vorname": "Wilhelm",
"Nachname": "von Montferrat"
}]
};
$(document).ready(function() {
$('#example').DataTable({
data: test.data,
columns: [
{ data: 'HistChar_ID' },
{ data: 'Vorname' },
{ data: 'Nachname' },
]
} );
} );
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Demo</title>
<script src="https://code.jquery.com/jquery-3.5.1.js"></script>
<script src="https://cdn.datatables.net/1.10.22/js/jquery.dataTables.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.22/css/jquery.dataTables.css">
<link rel="stylesheet" type="text/css" href="https://datatables.net/media/css/site-examples.css">
</head>
<body>
<div style="margin: 20px;">
<table id="example" class="display" style="width:100%">
<thead class="thead1">
<tr>
<th class="th1">HistChar_ID</th>
<th class="th2">Vorname</th>
<th class="th3">Nachname</th>
</tr>
</thead>
<tfoot class="tfoot1">
<tr>
<th class="th1">HistChar_ID</th>
<th class="th2">Vorname</th>
<th class="th3">Nachname</th>
</tr>
</tfoot>
</table>
</div>
</body>
</html>
JavaScript Data Sources
In the above example, the data is sourced from a JavaScript variable - so at the very least you always need to tell DataTables what the name of the JS variable is, using the data option.
And, you may also need to tell DataTables where the array of row data can be found in that variable. This is what we needed to do in the above example.
If the JavaScript variable had been structured like this (an array, not an object containing an array)...
var test = [ { ... }, { ... }, ... ];
...then in that case, we only need to use data: test in the DataTable.
Ajax Data Source
For Ajax-sourced data, things are slightly different. There is no JavaScript variable - there is only a JSON response.
By default, if that JSON response has the following structure (an array of objects called "data" - or an array of arrays)...
{ "data": [ { ... }, { ... }, ... ] }
...then you do not need to provide any additional instructions for DataTables to locate the array. It uses "data" as the default value.
Otherwise if you have a different JSON structure, you need to use the Ajax dataSrc option to specify where the array is in the JSON response.
For the above example, if you do not provide the dataSrc option, that is the same as providing the following:
ajax: {
url: "your URL here",
dataSrc: "data" // this is the default value - so you do not need to provide it
}
This is why your Ajax version "just works" when you only provide the URL:
ajax: 'RESOURCES/PHP/Searchfield.php'
DataTables is using the default value of data to find the array it needs.
And this is why it doesn't work when you use a JavaScript variable called test with data: test.
So, for JavaScript-sourced data, there is no default value. You always have to provide the JavaScript variable name - and maybe additional info for the location of the array in the varaible.
But for Ajax-sourced data, there is a default value (data) - and I believe this is only provided for backwards compatibility with older versions of DataTables.

how to give fixed table rows using typescript

I am using table for showing the datas and for data I am using Api.
Api data looks like::
{
"data": [
{
"id": "1",
"name": "name1",
"label": "label1"
},
{
"id": "2",
"name": "name2",
"label": "label2"
},
{
"id": "3",
"name": "name3",
"label": "label3"
}
]
}
html code
<table class="table table-striped">
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Label</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let data of sample;">
<td>{{data.id}}</td>
<td>{{data.name}}</td>
<td>{{data.label}}</td>
<tr>
<tbody>
<table>
I need the 10 table rows statically(fixed). The table data is from API. For exanple ,Api contains 2 data... Then UI table should be with 2 rows of data and balance with emply rows... but there should display 10 rows(Mandatory)
which means in UI i want 10 rows with data from Api and balance should be empty.
You can fix in view layer, ts layer or even backend API layer (Not really recommended).
In view layer if you loop over your data, you can calculate if your data's size goes over arbitrary threshold and if not loop again to display as many empty rows as possible.
In ts layer, when you receive data from api you can modify variable you pass to your view by adding to an array as many empty items as you need.
What's important if you use null, then you have to check for it with for example elvis operator.
I would advise agains adding to an array an object with all properties set to null, because then these are not so easily distinguishable from valid data from API and you can for instance make some rows interactive, even though they should not be.
const dataFromApi = [{ "id": "1", "name": "name1" }, { "id": "2", "name": "name2" }]
const minRowsNumber = 10;
const diff = minRowsNumber - dataFromApi.length;
const viewTableData = diff > 0 ? dataFromApi.concat(new Array(diff).fill(null)) : dataFromApi;
console.log(viewTableData)
Example in AngularJs (No Angular in SO Snippets, but it is the same principle)
angular.module('example', [])
.controller('ExampleController', function ExampleController() {
const dataFromApi = [{ "id": "1", "name": "name1" }, { "id": "2", "name": "name2" }]
const minRowsNumber = 10;
const diff = minRowsNumber - dataFromApi.length;
this.viewTableData = diff > 0 ? dataFromApi.concat(new Array(diff).fill(null)) : dataFromApi;
});
table {
border-collapse: collapse;
}
td, th {
border: 1px solid black
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<div ng-app="example" ng-controller="ExampleController as example">
<table>
<thead>
<tr>
<th>Id</th>
<th>Name</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="row in example.viewTableData track by $index">
<td>{{row ? row.id : ' '}}</td>
<td>{{row ? row.name : ' '}}</td>
</tr>
</tbody>
</table>
</div>

Applying style to particular cell in knockout JS dynamic table depending upon it value

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.

Angular JS nested ngRepeat loop how to break after maxRows are crossed the limit?

I have the below json structure stored in resultData:
{
"ParentObjects": [
{
"objId": "A1",
"ChildObjects": [
{
"description": "child object1"
},
{
"description": "child object2"
}
]
},
{
"objId": "A2",
"ChildObjects": [
{
"description": "child object3"
},
{
"description": "child object4"
},
{
"description": "child object5"
}
]
},
{
"objId": "A3",
"ChildObjects": [
{
"description": "child object6"
},
{
"description": "child object7"
}
]
}
]
}
I have 2 ng-repeat in my html as follows:
<table>
<tbody ng-repeat="parentObj in resultData">
<tr ng-repeat="childObj in parentObj.ChildObjects">
<td>{{childObj.description}}</td>
</tr>
</tbody>
</table>
I want to restrict the number of <tr> that will be displayed to 4 irrespective of number of parent and child in them. I know limitTo but it will apply only on inner loop and will not take account previously rendered rows by earlier parent objects.
Is it possible to restrict the rows considering/counting all child objects?
You can limit with limitTo in ng-repeat
<table>
<tbody ng-repeat="parentObj in resultData | limitTo:4">
<tr ng-repeat="childObj in parentObj.ChildObjects ">
<td>{{childObj.description}}</td>
</tr>
</tbody>
</table>
LimitTo will not work here, because each ng-repeat iteration creates a new scope and LimitTo will be restricted to that specific array or list('ChildObjects').
http://plnkr.co/edit/DrJpf4xiPq4AwtMKUQaU
<body ng-app="myApp">
<div ng-controller="myController">
<table>
<tbody ng-repeat="parentObj in resultData.ParentObjects">
<tr ng-repeat="childObj in parentObj.ChildObjects | limitTo:4">
<td>{{childObj.description}}</td>
</tr>
</tbody>
</table>
</div>
</body>
you can achieve this by setting index for each item in childObjects array.
http://plnkr.co/edit/pUQAvjkJXkn4JRBx1efh
<html ng-app="plunker">
<body ng-app="plunker">
<div ng-controller="MainCtrl">
<table ng-init="SetIndex()">
<tbody ng-repeat="parentObj in resultData.ParentObjects">
<tr ng-if="childObj.index < 4" ng-repeat="childObj in parentObj.ChildObjects">
<td>{{childObj.description}}</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
$scope.SetIndex = function () {
var item = 0;
angular.forEach($scope.resultData.ParentObjects, function (value, key) {
angular.forEach(value.ChildObjects, function (value1, key) {
value1.index = item;
item = item + 1;
});
});
}

Display data in a table by grouping them horizontally

I have some data that has the following format:
[name:'Name1', speed:'Val1', color:'Val2']
[name:'Name2', speed:'Val4', color:'Val5']
[name:'Name3', speed:'Val6', color:'Val7']
That I want to display in a table like this:
|Name1|Name2|Name3|
______|_____|______
speed |Val1 |Val4 |Val6
color |Val2 |Val5 |Val7
What I tried to do is group my data like this in the controller:
$scope.data = {
speeds: [{
...
},{
...
},{
...
}],
colors: [{
...
},{
...
},{
...
}],
};
But I am not sure what to put inside the empty areas, because all values there represent the values of the 'val1' variable for all Names (Accounts), and my tests until now keep failing.
You can imagine this as some sort of a comparisons matrix, that is used in order to see the all the values of the same variable across different accounts.
How can I represent the data in my model in order for me to successfully display them in a table as explained?
Edit
My difficulty lies in the fact that you create a table by going from row to row, so my html looks something like this:
<table md-data-table class="md-primary" md-progress="deferred">
<thead>
<tr>
<th ng-repeat="header in headers">
{{header.value}}
</th>
</tr>
</thead>
<tbody>
<tr md-auto-select ng-repeat="field in data">
<td ng-repeat="var in field">{{var.value}}</td>
</tr>
</tbody>
</table>
So as you can see I have a loop for each row, and a loop for each value of each row. This would be easier if I wanted to display the data horizontally, but I want the data vertically. So if we where talking about cars, we would have the car models as headers, and their respective characteristics(speed, color, etc) in each row.
If this is your basic structure:
var cols = [{name:'Name1', val1:'Val1', val2:'Val2'},
{name:'Name2', val1:'Val4', val2:'Val5'},
{name:'Name3', val1:'Val6', val2:'Val7'}];
This code
$scope.table = cols.reduce(function(rows, col) {
rows.headers.push({ value: col.name });
rows.data[0].push({ value: col.speed });
rows.data[1].push({ value: col.color });
return rows;
}, {headers:[], data:[[], []]});
will give you this structure for $scope.table:
$scope.table = {
headers : [{
value : "Name1"
}, {
value : "Name2"
}, {
value : "Name3"
}
],
data : [
[{
value : 'val1'
}, {
value : 'val4'
}, {
value : 'val6'
}
],
[{
value : 'val2'
}, {
value : 'val5'
}, {
value : 'val17'
}
]
]
};
<table md-data-table class="md-primary" md-progress="deferred">
<thead>
<tr>
<th ng-repeat="header in table.headers">
{{header.value}}
</th>
</tr>
</thead>
<tbody>
<tr md-auto-select ng-repeat="field in table.data">
<td ng-repeat="var in field">{{var.value}}</td>
</tr>
</tbody>
</table>
You could try this:
HTML
<table ng-app="myTable" ng-controller="myTableCtrl">
<thead>
<tr>
<th ng-repeat="car in cars">{{car.name}}</th>
</tr>
</thead>
<tbody>
<tr>
<td ng-repeat="car in cars">{{car.speed}}</td>
</tr>
<tr>
<td ng-repeat="car in cars">{{car.color}}</td>
</tr>
</tbody>
</table>
JS
angular.module("myTable",[])
.controller("myTableCtrl", function($scope) {
$scope.cars = [
{
name:'Name1',
speed:'Val1',
color:'Val2'
},
{
name:'Name2',
speed:'Val4',
color:'Val5'
},
{
name:'Name3',
speed:'Val6',
color:'Val7'
}
]
});
https://jsfiddle.net/ABr/ms91jezr/

Categories