Get calling table from column option - javascript

I have a few Bootstrap table on one page. Each table has some data attributes (like data-link="test-page" and so on). Besides that, one column of each Bootstrap table uses a column formatter, using data-formatter="actionFormatter". However, I want to get the current table data attributes when actionFormatter is called, so based on the data attributes I can return a string.
Both this and $(this) return an Object, which doesn't work. $(this).closest('table').data() doesn't work either, while I expected that one to be the most true.
Here's the code I use:
<th data-field="actions" data-formatter="actionFormatter" data-events="actionEvents">Actions</th>
this returns a JSON object with the row properties, and $(this).closest('table').data(XXX) return undefined. I expected it to return an array with all the data attributes.
Is there any way to get the current processing table from within the formatter?
Example code:
<!-- table 1 -->
<table
data-actions="edit,remove"
data-url="some/url"
>
<thead>
<tr>
<th data-formatter="actionFormatter">Actions</th>
</tr>
</thead>
</table>
<!-- table 2 -->
<table
data-actions="edit,remove"
data-url="some/url"
>
<thead>
<tr>
<th data-formatter="actionFormatter">Actions</th>
</tr>
</thead>
</table>
// actionFormatter:
function actionFormatter(value, row, index, field) {
// get data-actions from the right table somehow,
// and return a string based on data-url/other
// data attributes
}

It seems that when the action formatter is called, the execution context this is an object with all the bootstrap table row associated data as well as all the data-* attributes of the row.
Taking that into account you can add an id to each table and a data-table-id attribute to your rows like:
<table
id="table-1"
data-actions="edit,remove"
data-url="some/url"
>
<thead>
<tr>
<th data-formatter="actionFormatter" data-table-id="table-1">Actions</th>
</tr>
</thead>
so that in your formatter you can retrieve the table DOM Element by using that id:
function actionFormatter(value, row, index, field) {
// get data-actions from the right table somehow,
// and return a string based on data-url/other
// data attributes
var data = $('#' + this.tableId).data();
}

Related

ng-zorro antd, nz-table dynamic table columns and rows

I have a table where columns and row cells are dynamically set,
in the table header th content should be dynamic and also for table body tr maybe contain HTML that contains another component tag.
is there any way to handle that, I have created a component called table and this table has #Input and #Output to be reusable for different usage.
in the ng-zorro documentation, there is no way to use the table data source technique so I can use render functions like react and.
You can create two inputs, one for the columns and one for the rows.
To make the columns dynamically you have to send to the column input an array with column objects. There you can set everything that you want. I usually use the tittle and the column function like that:
listOfColumn = [
{
title: 'Code',
compare: (a: User, b: User) => a.code.localeCompare(b.code)
},
{
title: 'Customer',
compare: (a: User, b: User) => a.name.localeCompare(b.name)
}
]
The html code to use it is the following:
<thead>
<tr>
<th *ngFor="let column of listOfColumn" [nzSortFn]="column.compare">{{ column.title }}</th>
</tr>
</thead>
And for the data, just send it to other input and set the array as data input for the table and make a loop to display the content:
<nz-table
#basicTable
[nzData]="data">
<thead>
<tr>
<th *ngFor="let column of listOfColumn" [nzSortFn]="column.compare">{{ column.title }}</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let user of basicTable.data">
<td>{{ user.code }}</td>
<td>{{ user.name }}</td>
</tbody>
</nz-table>
I hope I answer your question :D

NodeJS: How can I scrape two different tables, that are visually part of the same table, into one JSON Object?

Here's an example of the table of data I'm scraping:
The elements in red are in the <th> tags while the elements in green are in a <td> tag, the <tr> tag can be displayed according to how they're grouped (i.e. '1' is in it's own <tr>; HTML snippet:
EDIT: I forgot to add the surrounding div
<div class="table-cont">
<table class="tg-1">
<thead>
<tr>
<th class="tg-phtq">ID</td>
</tr>
</thead>
<tbody>
<tr>
<td class="tg-0pky">1</td>
<td class="tg-0pky">2</td>
<td class="tg-0pky">3</td>
</tr>
</tbody>
</table>
<table class="tg-2">
<thead>
<tr>
<th class="tg-phtq">Sample1</td>
<th class="tg-phtq">Sample2</td>
<...the rest of the table code matches the pattern...>
</tr>
</thead>
<tbody>
<tr>
<td class="tg-0pky">Swimm</td>
<td class="tg-dvpl">1:30</td>
<...>
</tr>
</tbody>
<...the rest of the table code...>
</table>
</div>
As you can see, in the HTML they're actually two different tables while they're displayed in the above example as only one. I want to generate a JSON object where the keys and values include the data from the two tables as if they were one, and output a single JSON Object.
How I'm scraping it right now is a bit of modified javascript code I found on a tutorial:
EDIT: In the below, I've been trying to find a way to select all relevant <th> tags from both tables and insert them into the same array as the rest of the <th> tag array and do the same for <tr> in the table body; I'm fairly sure for the th I can just insert the element separately before the rest but only because there's a single one - I've been having problems figuring out how to do that for both arrays and make sure all the items in the two arrays map correctly to each other
EDIT 2: Possible solution? I tried using XPath Selectors and I can use them in devTools to select everything I want, but page.evaluate doesn't accept them and page.$x('XPath') returns JSHandle#node since I'm trying to make an array, but I don't know where to go from there
let scrapeMemberTable = async (page) => {
await page.evaluate(() => {
let ths = Array.from(document.querySelectorAll('div.table-cont > table.tg-2 > thead > tr > th'));
let trs = Array.from(document.querySelectorAll('div.table-cont > table.tg-2 > tbody > tr'));
// the above two lines of code are the main problem area- I haven't been
//able to select all the head/body elements I want in just those two lines of code
// just removig the table id "tg-2" seems to deselect the whole thing
const headers = ths.map(th => th.textContent);
let results = [];
trs.forEach(tr => {
let r = {};
let tds = Array.from(tr.querySelectorAll('td')).map(td => td.textContent);
headers.forEach((k,i) => r[k] = tds[i]);
results.push(r);
});
return results; //results is OBJ in JSON format
}
}
...
results = results.concat( //merge into one array OBJ
await scrapeMemberTable(page)
);
...
Intended Result:
[
{
"ID": "1", <-- this is the goal
"Sample1": "Swimm",
"Sample2": "1:30",
"Sample3": "2:05",
"Sample4": "1:15",
"Sample5": "1:41"
}
]
Actual Result:
[
{
"Sample1": "Swimm",
"Sample2": "1:30",
"Sample3": "2:05",
"Sample4": "1:15",
"Sample5": "1:41"
}
]

Jquery - Access table values (tr children - td) and change them

Found a few posts about this but none answered my question properly.
I want to access some values in my table and change them using a click function in js using jquery. How can I access this and change it without using innerHTML?
<table class="tg">
<tr>
<th class="tg-031e">Race</th>
<th class="tg-031e">space holder lol</th>
</tr>
</table>
var tableArray = $("table").children().children();
$("#input img.Majin").click(function() {
//tableArray[0].innerHTML = "";
});
Use following find function :
$("table").find('classname');

Looping over an array of objects with mustache

edit: updated this thread to clarify my question.
I make an ajax call that returns a dataset in json which looks like this:
Everything (including the correct column names) has already been taken care of via DB views so I wanted to write a script that just grabs a dataset and spits it out in a nicely formatted html table. This way the DB's table\view can be changed (columns added and removed) and the code will not have to be updated. I've been trying to get this to work with mustache but there doesn't seem to be a simple way of doing it. In the examples I find of people using mustache with an array of objects they are all explicitly referencing the objects properties in the template. I don't know the number or name of the objects' properties (the dataset's columns) will be a head of time so I can't enter them statically in the template.
Right now I'm using two templates, one for the headers and one just for the table rows:
<script id="datasetTable" type="text/template">
<table class="table table-hover table-bordered">
<thead>
<tr>
{{#headers}}
<th>{{.}}</th>
{{/headers}}
</tr>
</thead>
<tbody>
</tbody>
</table></script>
<script id="datasetTableRows" type="text/template">
<tr>
{{#rows}}
<td>{{.}}</td>
{{/rows}}
</tr>
</script>
And here is how I'm using it:
//Build table headers from dataset's columns
datasetCols = [];
for (var keyName in dataset[0]){
datasetCols.push(keyName);
};
//Build table rows from dataset rows
var renderedTableRows = '';
var tplRows = document.getElementById('datasetTableRows').innerHTML;
datasetLength = dataset.length;
for (var i=0; i<datasetLength; i++) {
var currentRow = dataset[i];
var rowValues = [];
for (var prop in currentRow){
rowValues.push(currentRow[prop]);
}
var renderedHtml = Mustache.render(tplRows, {rows: rowValues});
renderedTableRows += renderedHtml;
}
//render table with headers
var $renderedTable = $(Mustache.render('datasetTable', {headers: datasetCols}));
$renderedTable.find('tbody').html(renderedTableRows);
$(htmlContainer).html($renderedTable);
This works fine, but I really would like to simplify it further by using only one template. Can mustache process this in a more efficient way- without me having to explicitly reference the objects properties' names in the template?
I'd also like to add that I am already using mustache in a bunch of other places (code I don't feel like re-writing with a new engine right now) so if mustache can't do it I'll stick to pure js for the time being.
I've not personally used moustache, but they're all very similar.
Also, since it is logic-less you really want to return a more useful format. I.e an array of arrays would be better in this instance.
[["234", "ddg", "aa"], ["and, so on", "and so on", "and so on"]]
But if you know that there will always be three columns returned, you could do something like:
<table class="table table-hover table-bordered">
<thead>
<th> Whatever your headers are </th>
</thead>
<tbody>
{{#.}}
<tr>
<td>{{col1}}</td>
<td>{{col2}}</td>
<td>{{col3}}</td>
</tr>
{{/.}}
<tbody>
</table>
Or enumerate the object:
<table class="table table-hover table-bordered">
<thead>
<th> Whatever your headers are </th>
</thead>
<tbody>
{{#.}}
<tr>
{{#each dataSet}}
<td>{{this}}</td>
{{/each}}
</tr>
{{/.}}
<tbody>
</table>
Also, when creating HTML in javascript, use an array, it's faster.
var somehtml = [];
somehtml.push('something');
somehtml.push('something else');
somehtml = somehtml.join('');

table mapping by th and first td in row to populate from json object

using php to echo json array inline i want js/jquery to populate table according to these data.
HTML table
<table>
<thead>
<tr>
<th>Time</th>
<th data-day='2013-03-15'>15-3</th>
<th data-day='2013-03-16'>16-3</th>
<th data-day='2013-03-17'>17-3</th>
</tr>
</thead>
<tbody>
<tr data-time='09'>
<td>9am</td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<script>
var arr=[
{"date":"2013-03-15","id":"4","time_booked":"09:00:00"},
{"date":"2013-03-15","id":"1","time_booked":"09:10:00"},
{"date":"2013-03-17","id":"5","time_booked":"09:30:00"}
];
$.each(arr,function(){
console.log('id:'+this.id+'inside:'+this.date+'|'+this.time_booked);
});
</script>
i want to loop thro arr and according to its date and time_booked write id inside td.
for example first row will go to td with date-day='2013-03-15' and data-time='09'
so how can i do this using javascript ?
im thinking should i include data-day,data-time inside each td in tbody ? or is there a better way to do it ?
current approach:
include data-day inside each tr so html of tbody is
<tr data-time='09'>
<td data-day='2013-03-15'></td>
<td data-day='2013-03-16'></td>
etc..
</tr>
then use js
$.each(arr,function(){
var rday=this.date;
var rtime=this.time_booked;
var sel='tr[data-hr="'+rtime.substr(0,2)+'"]';
var dom=$(sel).find('td[data-day="'+rday+'"]').first();
if(dom.length)dom.append(this.id);
});
but i have a feeling its stupid ! there must be a way to map table using x,y (table head,row head) or there is none ?
I think the jQuery index function is what you're looking for. In the code sample below, I've used it to fetch the colIndex for the date. In this case, it fetches all of the th cells within the table, and uses .index(..) with a selector seeking the required date. This gives the column index of the date you're seeking, and from there it's all pretty straight-forward.
var arr=[
{"date":"2013-03-15","id":"4","time_booked":"0900"},
{"date":"2013-03-15","id":"1","time_booked":"0910"},
{"date":"2013-03-17","id":"5","time_booked":"0930"}
];
$.each(arr,function(){
var cell = GetCellByDateAndTime(this.date, this.time_booked);
$(cell).text(this.id);
});
function GetCellByDateAndTime(date, time) {
var colIndex = $("#BookingsTable th").index($("[data-day='" + date + "']"));
var row = $("#BookingsTable tr[data-time='" + time + "']")
var cell = $(row).children($("td"))[colIndex];
return cell;
}
And a Fiddle.

Categories