Knockout Table View of Array list without Names - sql

I'm new to knockout and JS programming. I have a JSON result set returned, that would be two nested arrays, like this wherein each array could be variable in size:
listToReturn
[0] Count:4 -------> [0] "CHANNEL", [1] "HOUR", [2] "DATE", [3] "TRANSACTION_CNT"
[1] Count:122 ----->
[0] 101, [1] 11, [2] 03/01/2014, [3] 400,
[4] 101, [5] 6, [7] 03/12/2014, [8] 232
(these are the individual values for the rows above that repeat)
I want to build table that displays these nicely. Essentially, that will handle any result set that comes back with variable number of columns and data that will be populated in the table, like this:
CHANNEL HOUR DATE TRANSACTION_CNT
101 12 03/01/2014 400
101 6 03/12/2014 232
I have the first part working for the column headers:
Within ViewModel:
$.ajax({
type: 'get',
url: 'Reports/GetReportData',
data: { requestObj: req },
contenttype: 'application/json',
datatype: 'json',
success: function(result) {
if (result) {
document.getElementById("reportOutputfieldSet").style.display = "block";
ko.utils.arrayForEach(result[0], function (data) {
self.cnames.push(data.replace(",", " "));
});
ko.utils.arrayForEach(result[1], function (data) {
self.cdata.push(data.replace(",", " "));
});
In the View:
<tr data-bind="foreach: cnames" style="color: white; background-color: #003399; font-weight: bold; width: 600px">
<td data-bind="text: $data" style="width: 25%"></td>
</tr>
After several different attempts to properly construct a display for the data, I'm coming up empty handed. I first tried going through and getting the unique values for each one and displaying them in the UI, but that didn't work. :(
var noColumns = result[0].length;
var thisArray = function () {
if (result[1].length === 0)
return [];
for (var column = 0; column < result[0].length - 1; column++) {
for (var row = column; row < result[1].length - 1; row++) {
if (row % noColumns == 0) {
switch (column) {
case 0:
self.columnOne.push(result[1][row]);
break;
case 1:
self.columnTwo.push(result[1][row]);
break;
}
}
}
}
return self.columnOne();
};
In the View:
<tbody>
<!-- ko foreach: columnOne -->
<tr style="border-bottom: solid 1px #003399;">
<td data-bind="text: $data" style="width: 25%"></td>
<!-- ko foreach: columnTwo -->
<td data-bind="text: $data" style="width: 25%"></td>
<!-- /ko -->
</tr>
<!-- /ko -->
</tbody>
I have a feeling I need a custom ko.binding, but really at a loss as to how to get started with it. Anyone's help is greatly appreciated. Thanks in advance!

Related

how to apply filter on JQuery DataTable each columns? [duplicate]

I'm trying to filter table rows in an intelligent way (as opposed to just tons of code that get the job done eventually) but a rather dry of inspiration.
I have 5 columns in my table. At the top of each there is either a dropdown or a textbox with which the user may filter the table data (basically hide the rows that don't apply)
There are plenty of table filtering plugins for jQuery but none that work quite like this, and thats the complicated part :|
Here is a basic filter example http://jsfiddle.net/urf6P/3/
It uses the jquery selector :contains('some text') and :not(:contains('some text')) to decide if each row should be shown or hidden. This might get you going in a direction.
EDITED to include the HTML and javascript from the jsfiddle:
$(function() {
$('#filter1').change(function() {
$("#table td.col1:contains('" + $(this).val() + "')").parent().show();
$("#table td.col1:not(:contains('" + $(this).val() + "'))").parent().hide();
});
});
Slightly enhancing the accepted solution posted by Jeff Treuting, filtering capability can be extended to make it case insensitive. I take no credit for the original solution or even the enhancement. The idea of enhancement was lifted from a solution posted on a different SO post offered by Highway of Life.
Here it goes:
// Define a custom selector icontains instead of overriding the existing expression contains
// A global js asset file will be a good place to put this code
$.expr[':'].icontains = function(a, i, m) {
return $(a).text().toUpperCase()
.indexOf(m[3].toUpperCase()) >= 0;
};
// Now perform the filtering as suggested by #jeff
$(function() {
$('#filter1').on('keyup', function() { // changed 'change' event to 'keyup'. Add a delay if you prefer
$("#table td.col1:icontains('" + $(this).val() + "')").parent().show(); // Use our new selector icontains
$("#table td.col1:not(:icontains('" + $(this).val() + "'))").parent().hide(); // Use our new selector icontains
});
});
This may not be the best way to do it, and I'm not sure about the performance, but an option would be to tag each column (in each row) with an id starting with a column identifier and then a unique number like a record identifier.
For example, if you had a column Produce Name, and the record ID was 763, I would do something like the following:
​​<table id="table1">
<thead>
<tr>
<th>Artist</th>
<th>Album</th>
<th>Genre</th>
<th>Price</th>
</tr>
</thead>
<tbody>
<tr>
<td id="artist-127">Red Hot Chili Peppers</td>
<td id="album-195">Californication</td>
<td id="genre-1">Rock</td>
<td id="price-195">$8.99</td>
</tr>
<tr>
<td id="artist-59">Santana</td>
<td id="album-198">Santana Live</td>
<td id="genre-1">Rock</td>
<td id="price-198">$8.99</td>
</tr>
<tr>
<td id="artist-120">Pink Floyd</td>
<td id="album-183">Dark Side Of The Moon</td>
<td id="genre-1">Rock</td>
<td id="price-183">$8.99</td>
</tr>
</tbody>
</table>
You could then use jQuery to filter based on the start of the id.
For example, if you wanted to filter by the Artist column:
var regex = /Hot/;
$('#table1').find('tbody').find('[id^=artist]').each(function() {
if (!regex.test(this.innerHTML)) {
this.parentNode.style.backgroundColor = '#ff0000';
}
});
You can filter specific column by just adding children[column number] to JQuery filter. Normally, JQuery looks for the keyword from all the columns in every row. If we wanted to filter only ColumnB on below table, we need to add childern[1] to filter as in the script below. IndexOf value -1 means search couldn't match. Anything above -1 will make the whole row visible.
ColumnA | ColumnB | ColumnC
John Doe 1968
Jane Doe 1975
Mike Nike 1990
$("#myInput").on("change", function () {
var value = $(this).val().toLowerCase();
$("#myTable tbody tr").filter(function () {
$(this).toggle($(this.children[1]).text().toLowerCase().indexOf(value) > -1)
});
});
step:1 write the following in .html file
<input type="text" id="myInput" onkeyup="myFunction()" placeholder="Search for names..">
<table id="myTable">
<tr class="header">
<th style="width:60%;">Name</th>
<th style="width:40%;">Country</th>
</tr>
<tr>
<td>Alfreds Futterkiste</td>
<td>Germany</td>
</tr>
<tr>
<td>Berglunds snabbkop</td>
<td>Sweden</td>
</tr>
<tr>
<td>Island Trading</td>
<td>UK</td>
</tr>
<tr>
<td>Koniglich Essen</td>
<td>Germany</td>
</tr>
</table>
step:2 write the following in .js file
function myFunction() {
// Declare variables
var input, filter, table, tr, td, i;
input = document.getElementById("myInput");
filter = input.value.toUpperCase();
table = document.getElementById("myTable");
tr = table.getElementsByTagName("tr");
// Loop through all table rows, and hide those who don't match the search query
for (i = 0; i < tr.length; i++) {
td = tr[i].getElementsByTagName("td")[0];
if (td) {
if (td.innerHTML.toUpperCase().indexOf(filter) > -1) {
tr[i].style.display = "";
} else {
tr[i].style.display = "none";
}
}
}
}

Dynamically Tally Child Elements by Classname in Vue

I have a page that allows a user to drag/drop images into pre-defined DIVs, then I tally up the total value of the images based on their class name. What I am trying to do is get vue to read the values from each outer div.answer and get the class names of the child images.
My source code is:
<div
is="box-answers"
v-for="box in boxes.slice().reverse()"
v-bind:key="box.id"
v-bind:level="box.level"
v-bind:hint="box.hint"
></div>
<script>
Vue.component('box-answers', {
props: ['level','hint'],
template: '<div class="droppable answer :id="level" :title="hint"></div>'
});
new Vue({
el: '#mainapp',
data: {
boxes: [
{ id: 1, level: 'baselevel-1', hint: 'x 1' },
{ id: 2, level: 'baselevel-2', hint: 'x 20' },
{ id: 3, level: 'baselevel-3', hint: 'x 400' },
{ id: 4, level: 'baselevel-4', hint: 'x 8,000' },
{ id: 5, level: 'baselevel-5', hint: 'x 160,000' }
]
}
</script>
This converts to the follow HTML (the nested DIVs and SPANs are user-possible entries by dragging):
<div id="baselevel-5" class="droppable answer" title="x 160,000">
<div><img src="images/line.gif" alt="Five" class="imgfive"></div>
<span><img src="images/dot.gif" alt="One" class="imgone"></span>
</div>
...
<div id="baselevel-1" class="droppable answer" title="x 1">
<span><img src="images/line.gif" alt="One" class="imgone"></span>
</div>
Currently, I have jQuery/JavaScript calculating the point values using the following:
$(function(j) {
var arAnswers = Array(1);
count = 0; //
j("div.answer").each(function( idx ) {
currentId = j(this).attr('id');
ones = 0;
fives = 0;
if ( j("#" + currentId).children().length > 0 ) {
ones = j("#" + currentId).children().find("img.imgone").length * 1;
fives = j("#" + currentId).children().find("img.imgfive").length * 5;
arAnswers[count] = ones + fives; //Tally box value
count++;
}
});
});
I would like Vue to perform similar iteration and addition to return total value of ones and fives found based on the image classname.
Currently, you are approaching this problem as a pure-play DOM operation. If that is what you need then you can simply use $refs:
<!-- NOTICE ref -->
<div ref="boxAnswers"
is="box-answers"
v-for="box in boxes.slice().reverse()"
v-bind:key="box.id"
v-bind:level="box.level"
v-bind:hint="box.hint">
</div>
Inside your high-level component, you will have a function like:
function calculate() {
// NOTICE $refs
const arAnswers = this.$refs.boxAnswers.map((x) => {
// $el is the DOM element
const once = x.$el.querySelectorAll('img.imgone').length * 1;
const fives = x.$el.querySelectorAll('img.imgfive').length * 5;
return once + fives
});
return arAnswers;
}
But this is not the correct Vue way of doing things. You have to think in terms of events and data model (MVVM - don't touch DOM. DOM is just a representation of your data model). Since, you have a drag-n-drop based application, you have to listen for drag, dragstart, dragend and other drag events. For example:
<!-- NOTICE drop event -->
<div #drop="onDropEnd(box, $event)"
is="box-answers"
v-for="box in boxes.slice().reverse()"
v-bind:key="box.id"
v-bind:level="box.level"
v-bind:hint="box.hint">
</div>
Your onDropEnd event handler will look like:
function onDrop(box, $event) {
// box - on which box drop is happening
// $event.data - which image is being dropped
// Verify $event.data is actually the image you are intending
if ($event.data === 'some-type-image') {
// Do the counting manipulations here
// ... remaining code
}
}
This is not a complete code as I don't know other components. But it should help you with the required direction.

Angular Material Table Dynamic Columns without model

I need to use angular material table without model, because I don't know what will come from service.
So I am initializing my MatTableDataSource and displayedColumns dynamically in component like that :
TableComponent :
ngOnInit() {
this.vzfPuanTablo = [] //TABLE DATASOURCE
//GET SOMETHING FROM SERVICE
this.listecidenKisi = this.listeciServis.listecidenKisi;
this.listecidenVazife = this.listeciServis.listecidenVazife;
//FILL TABLE DATASOURCE
var obj = {};
for (let i in this.listecidenKisi ){
for( let v of this.listecidenVazife[i].vazifeSonuclar){
obj[v.name] = v.value;
}
this.vzfPuanTablo.push(obj);
obj={};
}
//CREATE DISPLAYED COLUMNS DYNAMICALLY
this.displayedColumns = [];
for( let v in this.vzfPuanTablo[0]){
this.displayedColumns.push(v);
}
//INITIALIZE MatTableDataSource
this.dataSource = new MatTableDataSource(this.vzfPuanTablo);
}
The most important part of code is here :
for( let v in this.vzfPuanTablo[0]) {
this.displayedColumns.push(v);
}
I am creating displayedColumns here dynamically, it means; even I don't know what will come from service, I can show it in table.
For example displayedColumns can be like that:
["one", "two" , "three" , "four" , "five" ]
or
["stack","overflow","help","me]
But it is not problem because I can handle it.
But when I want to show it in HTML, I can't show properly because of
matCellDef thing:
TableHtml :
<mat-table #table [dataSource]="dataSource" class="mat-elevation-z8">
<ng-container *ngFor="let disCol of displayedColumns; let colIndex = index" matColumnDef="{{disCol}}">
<mat-header-cell *matHeaderCellDef>{{disCol}}</mat-header-cell>
<mat-cell *matCellDef="let element "> {{element.disCol}}
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
</mat-table>
My problem is here:
<mat-cell *matCellDef="let element "> {{element.disCol}} < / mat-cell>
In fact, I want to display element."disCol's value" in the cell, but I don't know how can I do that.
Otherwise, everything is ok except this element."disCol's value" thing.
When I use {{element.disCol}} to display value of element that has disCols's value , all cells are empty like that:
Other example that using {{element}} only:
Also as you can see:
Table datasource is changing dynamically. It means I can't use {{element.ColumnName}} easily, because I don't know even what is it.
First Example's displayedColumns = ['Vazife', 'AdSoyad', 'Kirmizi', 'Mavi', 'Yesil', 'Sari'];
Second Example's displayedColumns = ['Muhasebe', 'Ders', 'Egitim', 'Harici'];
matHeaderCellDef is correct , because it is using {{disCol}} directly.
But I need to read disCol's value, and display element.(disCol's value) in the cell.
How can I do that ?
I found solution :)
It is very very easy but i could't see at first :)
only like that :
<mat-cell *matCellDef="let element "> {{element[disCol]}}
</mat-cell>
I must use {{element[disCol]}} only in HTML.
Now , everything is ok:)
For a full working example based on #mevaka's
Where jobDetails$ is the array of items.
columns$ is equvilent to Object.keys(jobDetails$[0]) so is just a string[]
<table mat-table [dataSource]="jobDetails$ | async">
<ng-container *ngFor="let disCol of (columns$ | async); let colIndex = index" matColumnDef="{{disCol}}">
<th mat-header-cell *matHeaderCellDef>{{disCol}}</th>
<td mat-cell *matCellDef="let element">{{element[disCol]}}</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="(columns$ | async)"></tr>
<tr mat-row *matRowDef="let row; columns: (columns$ | async)"></tr>
</table>
I've tried my best to boil a dynamic table down to the minimum. This example will display any columns given an array of flat objects with any keys. Note how the first object has an extra "foo" property that causes an entire column to be created. The DATA const could be some data you get from a service. Also, you could add a "column ID -> label" mapping into this if you know some common property names you'll be getting the JSON. See the stachblitz here.
import {Component, ViewChild, OnInit} from '#angular/core';
const DATA: any[] = [
{position: 1, name: 'sdd', weight: 1.0079, symbol: 'H', foo: 'bar'},
{position: 2, name: 'Helium', weight: 4.0026, symbol: 'He'},
{position: 3, name: 'Lithium', weight: 6.941, symbol: 'Li'},
{position: 4, name: 'Beryllium', weight: 9.0122, symbol: 'Be'},
{position: 5, name: 'Boron', weight: 10.811, symbol: 'B'},
{position: 6, name: 'Carbon', weight: 12.0107, symbol: 'C'}
];
#Component({
selector: 'dynamic-table-example',
styleUrls: ['dynamic-table-example.css'],
templateUrl: 'dynamic-table-example.html',
})
export class DynamicTableExample implements OnInit {
columns:Array<any>
displayedColumns:Array<any>
dataSource:any
ngOnInit() {
// Get list of columns by gathering unique keys of objects found in DATA.
const columns = DATA
.reduce((columns, row) => {
return [...columns, ...Object.keys(row)]
}, [])
.reduce((columns, column) => {
return columns.includes(column)
? columns
: [...columns, column]
}, [])
// Describe the columns for <mat-table>.
this.columns = columns.map(column => {
return {
columnDef: column,
header: column,
cell: (element: any) => `${element[column] ? element[column] : ``}`
}
})
this.displayedColumns = this.columns.map(c => c.columnDef);
// Set the dataSource for <mat-table>.
this.dataSource = DATA
}
}
<mat-table #table [dataSource]="dataSource">
<ng-container *ngFor="let column of columns" [cdkColumnDef]="column.columnDef">
<mat-header-cell *cdkHeaderCellDef>{{ column.header }}</mat-header-cell>
<mat-cell *cdkCellDef="let row">{{ column.cell(row) }}</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
</mat-table>

Srpy dataset if decision based on value from different dataset

Many thanks for reading this.
I have asked as well in Adobe forums with no luck.
I am building a small library application for school books.
I have created a database with lets say 2 tables
Books ( ID_Book , Writer , Title , Copies) and
Loans ( ID_Book , Load_ID , Loan_Date ) etc
I have used correctly spry to create easily a table which print the book list in a table
with pagination .
var ds1 = new Spry.Data.XMLDataSet("ajaxquery.php", "root/row", {sortOnLoad: "Writer", sortOrderOnLoad: "ascending"});
ds1.setColumnType("ID_Book", "number");
var pv1 = new Spry.Data.PagedView( ds1 ,{ pageSize:10 });
var pv1PagedInfo = pv1.getPagingInfo();
pv1.setColumnType("ID_Book", "number");
I have made the necessary declarations to produce the dataset for the Loans
var ds3 = new Spry.Data.XMLDataSet("ajaxallloans", "root/row", {sortOnLoad: "ID_Book", sortOrderOnLoad: "ascending"});
ds3.setColumnType("ID_Book", "number");
ds3.setColumnType("ID_Dan", "number");
I would like to find a way to change the table row color for the BOOKS table IF an ID_Book is within the Loans table - ds3.
The table is created
<div spry:region="pv1" id="bibliapv">
<div spry:state="loading" class="loading" >Loading...</div>
<div spry:state="ready">
<table>
<tr >
<th width="75" spry:sort="ID_Book"> Book No</th>
<th width="123" spry:sort="Writer">Writer </th>
etc...
</tr>
<tr spry:repeat="pv1" spry:select="mySelectClass" spry:hover="hover">
<td >{ID_Book}</td>
<td>{writer}</td>
etc ..
</tr>
</table>
</div>
</div>
<div>
Many thanks again.
Dinos - Greece
Many thanks again for reading .
I found a solution based on the ideas drawn from
labs.adobe.com/technologies/spry/samples/data_region/CustomColumnsSam ple.html
I have added the following code:
created a css rule
lets say
.match {
background-color: #0CF;
}
In spry:region add the class {cssrule} which is added dynamically shortly after <tr class="{cssrule}" spry:repeat="pv1" spry:select="mySelectClass" spry:hover="hover">
3.
Then just before closing tag added (you could put it earlier in code)
<script type="text/javascript">
ds2.addObserver({
onPostLoad:function( ds2, data ){
var data = ds2.getData();
var pv1data = pv1.getData();
for( var i = 0; i < pv1data.length; i++ )
{
for (var j =0 ; j< data.length ; j++)
{ if ((data[j].Writer).toString()== (pv1data[i].Writer).toString() ) //or whatever you like!
{pv1data[i].cssrule="match"; }
}
}
}
});
</script>

Unable to Show Data insde dojox.grid.DataGrid with dojo.data.ItemFileReadStore

I am using DOJO ItemFileReadStore with dojox.grid.DataGrid to show Data Inside a Grid
Please see the Image here
http://imageshare.web.id/viewer.php?file=kdfvrkmn6k7xafmi4jdy.jpg
EMployee.Java
public class Employee {
String name;
String dept;
// Setters and Getters
}
This is My Servlet
response.setContentType("text/x-json;charset=UTF-8");
response.setHeader("Cache-Control", "no-cache");
PrintWriter out = response.getWriter();
List list = new ArrayList();
Employee emp1 = new Employee();
Employee emp2 = new Employee();
emp1.setDept("CSE");
emp1.setName("Vamsi");
emp2.setDept("EEE");
emp2.setName("Raju");
list.add(emp1);
list.add(emp2);
List jsonresponse = new ArrayList();
for (int i = 0; i < list.size(); i++) {
JSONObject nextObject = new JSONObject();
nextObject.put("name", list.get(i));
jsonresponse.add(nextObject);
}
JSONObject json = new JSONObject();
json.put("label", "name");
json.put("items", jsonresponse.toArray());
response.getWriter().write(json.toString());
}
This is MY JSP Page
<body class=" claro ">
<span dojoType="dojo.data.ItemFileReadStore" jsId="store1" url="http://localhost:8080/Man/MyServlet2"></span>
<table dojoType="dojox.grid.DataGrid" store="store1"
style="width: 100%; height: 500px;">
<thead>
<tr>
<th width="150px" field="name">Name</th>
<th width="150px" field="dept">Dept</th>
</tr>
</thead>
</table>
Please see the Image here
http://imageshare.web.id/viewer.php?file=kdfvrkmn6k7xafmi4jdy.jpg
Please help , Thank you .
+1 for posting the server output (firebug screenshot) in your question. This makes a lot easier for people to help you - for example I can easily see that the data format is still not quite right. You are getting better at both dojo and stackoverflow, it seems!
Remember that the ItemFileReadStore expects the data to be in a particular format. Your servlet is producing:
{label: "name", items: [
{name: {dept: "CSE", name: "Vansi"}},
{name: {dept: "ABC", name: "Abcd"}}
]}
You see you are telling the store that each item's "name" is an object with some properties ("dept" and "name"). This is why the grid shows object Object in the name column. It should be:
{label: "name", items: [
{dept: "CSE", name: "Vansi"},
{dept: "ABC", name: "Abcd"}
]}
I'm not very good with java, but I believe only a small change in your servlet is required:
// The for loop that adds employees to jsonresponse.
for (int i = 0; i < list.size(); i++)
{
// Instead of adding the
Emloyee e = (Employee)list.get(i);
JSONObject nextObject = new JSONObject();
nextObject.put("name", e.getName());
nextObject.put("dept", e.getDept());
jsonresponse.add(nextObject);
}
In fact, it's possible that you can just do json.put("items", list.toArray()); instead of adding each employee to jsonresponse.