I'd like to filter dynamically a flask generated table thanks to a variable set in JavaScript from another similar table.
Unfortunately, it seems that Javascript variables cannot be reused in Jinja2 contexts (because jinja2 contexts are run prior to Javascript).
In the example below, I'd like to filter the tasks with the project_id. This project_id was set thanks to the value selected in another table.
Note: I'd like to avoid to reload the page thanks to this solution.
{% for Task in mytasks %}
{% if Task.project_id == var_project_id %} <- Not working, the javascript variable is not recognized
<tr class="clickable-row">
<td style="display:none;"> {{ Task.task_id }} </td>
<td style="display:none;"> {{ Task.project_id }} </td>
<td>{{ Task.title }}</td>
<td class="task_description" > {{ Task.description }} </td>
<td class="task_creation_date"> {{ Task.creation_date }} </td>
</tr>
{% endfor %}
I've found a solution thanks to a simple javascript function.
Here is it, just in case some one else has the same issue:
<script>
//The project id is defined when the project is selected in a hover table
$('#myTableProject tbody tr').click(function (event) {
$('tr').not(this).removeClass('highlight');
$(this).addClass('highlight');
project_id = $(this).find('td.project_id').text();
//...
var tableTasks;
tableTasks = document.getElementById("myTableTasks");
tr = tableTasks.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")[1];// [1] is the column number you want to filter
if (td) {
//each cell of the column [1] is compared to the project id
if (td.innerHTML.toUpperCase().indexOf(project_id) > -1) {
tr[i].style.display = "";//the data is displayed
} else {
tr[i].style.display = "none";//the data is hidden
}
} }
</script>
More info:
https://www.w3schools.com/howto/howto_js_filter_table.asp
Related
In my angular app i display JSON data in a table with pagination using ngx-pagination i want to export my table in pdf format I used a couple of npm packages that take a screenshot off the HTML page and convert it to a pdf to export, the only problem is not all the data is being displayed because of the pagination and number of items per page, is there a work around this?
Here is the code I used :
<table
class="
table
is-hoverable is-striped is-fullwidth
content-table
#userTable
"
id="htmlData"
>
<thead>
<tr>
<th>{{ "DataSource.RecordID" | translate }}</th>
<th colspan="6">{{ "DataSource.Details" | translate }}</th>
</tr>
</thead>
<tbody>
<tr
*ngFor="
let row of FilteredMatchTransactions
| paginate: { itemsPerPage: itemsPerPage, currentPage: p };
let i = index
"
>
<td>
{{ "DataSource.SessionID" | translate }} :
{{ row.SESSION_ID }}
</td>
<td>
{{ "DataSource.ExternalStan" | translate }} :
{{ row.EXTERNAL_STAN }}
</td>
<td>
PAN :
{{ row.CARD_NUMBER }}
</td>
<td>
{{ "DataSource.Amount" | translate }} :
{{ row.TRANSACTION_AMOUNT.split(" ")[0] }}
</td>
<td>
{{ "DataSource.Currency" | translate }} :
{{ row.TRANSACTION_AMOUNT.split(" ")[1] }}
</td>
<td>
Terminal :
{{ row.TERMINAL_ID }}
</td>
<td>
{{ "DataSource.TransactionDate" | translate }} :
{{ row.TRANSACTION_DATE }}
</td>
</tr>
</tbody>
</table>
ts :
import jsPDF from 'jspdf';
import html2canvas from 'html2canvas';
....
....
public downloadPDF(): void {
let DATA = document.getElementById('htmlData');
console.log(DATA);
html2canvas(DATA).then((canvas) => {
let fileWidth = 208;
let fileHeight = (canvas.height * fileWidth) / canvas.width;
const FILEURI = canvas.toDataURL('image/png');
let PDF = new jsPDF('p', 'mm', 'a4');
let position = 0;
PDF.addImage(FILEURI, 'PNG', 0, position, fileWidth, fileHeight);
PDF.save('angular-demo.pdf');
});
}
my idea is about to use a temporary created table DOM element instead of using angular active table (situated in the view), this is an overview of the idea:
// I suppose that this jsonApiData is an array got from API which you used it in DataSource and containing all data without pagination, so you should be sure that you already loaded all data from the API before performing any data manipulation or consumption:
private jsonApiData;
public downloadPDF(): void {
/*let table = document.getElementById('htmlData');*/
// refer to getTemporaryTableDom method below
let table = this.getTemporaryTableDom(this.jsonApiData);
html2canvas(table).then((canvas) => {
...
...
// Important: after finishing your save, remove the temporary table DOM from the memory
table.remove(); ==> to free up your memory.
});
}
...
...
/** this method will create a temporary table dom,
* and fill it with your api data.
**/
private getTemporaryTableDom(jsonData){
let t = document.createElement('table');
// fill your DOM Html table with your api data
for(let [index,obj] of Object.entries(jsonData)){
let newInsertedRow = t.insertRow(index);
// to insert cells and its values you can also use loop, i will let you free to chose
c = newInsertedRow.insertCell(0); // example SessionID
c.innerHTML = obj.SessionId; // SessionID value
c = r.insertCell(1); // example: ExternalStan
c.innerHTML = obj.ExternalStan; // ExternalStan value
...
...
}
return t; // to return the DOM TAble html element
}
This is just an idea to make sure you are using static data so that you will be able to control it without any problem, because using the angular view Doms can make things more difficult to manage because they are based on many concepts like ChangeDetection, component lifecycle, etc..
for more table dom manipulation details, you can refer to these ressources:
https://developer.mozilla.org/en-US/docs/Web/API/HTMLTableElement
https://stackoverflow.com/a/2324826/8678900
I developed a web project where I can upload two files and django server execute a function to return the lines that don't match with other in a pandas dataframe which is renderized in a html template. Is returned a two columns table, file1 and file2. I would like to have another column with the text and text difference 'highlighted'. I have no knowledge about javascript programing, but I don't know how to apply the function on each table row.
My views.py
def index(request):
form = UploadFileForm(request.POST, request.FILES)
if request.method == 'POST':
if form.is_valid():
check = CheckFiles(form.cleaned_data["arquivo1"], form.cleaned_data["arquivo2"]).verifica_tamanho()
if type(check) == str:
return HttpResponse('The file are the same!')
#return HttpResponse(check.to_html())
return render(request, 'index2.html', {'check': check})
else:
print('Invalid Form!')
return render(request, 'index.html', {'form': form})
and in my index2.html:
<table class="table" border="1px">
<thead class="thead-dark">
<tr>
<th scope="col">Original File</th>
<th scope="col">Secondary File</th>
</tr>
</thead>
<tr>
{% for _, record in check.iterrows %}
<tr>
{% for value in record %}
<td>{{ value }}</td>
{% endfor %}
</tr>
{% endfor %}
</tr>
</table>
and the highlight javascript function is:
highlight($("#new"), $("#old"));
function highlight(newElem, oldElem){
var oldText = oldElem.text(),
text = '';
newElem.text().split('').forEach(function(val, i){
if (val != oldText.charAt(i))
text += "<span class='highlight'>"+val+"</span>";
else
text += val;
});
newElem.html(text);
}
.highlight {background-color: #B4D5FF}
So, I need some help to understand how to apply this javascript function on each table row.
Thank you, have a nice day.
I can see you also use jquery so:
$(.table tr).each(function(index){
$(this).addClass("highlight");
});
that way you can apply highlight to every row.
It seems like your current highlight function "highlights" chars that have changed in the string but I have no idea what it has to do with rows... What is $("#new") ... what is $("#old")...
**UPDATE **
$("table tr").each(function(index){
a = $(this).find("td");
first_td = a.eq(0);
second_td = a.eq(1);
highlight(second_td, first_td);
});
I am using flask.
I pass 4 different lists into the HTML file, loop through them and put their value in the table
{% for (s_pid, s_name, s_cpu_percent, s_memory_percent) in zip(pid, name, cpu_percent, memory_percent)%}
<tr>
<td id="task-pid">{{s_pid}}</td>
<td id="task-name">{{s_name}}</td>
<td id="task-cpu-percent">{{s_cpu_percent}}</td>
<td id="task-memory-percent">{{s_memory_percent}}</td>
</tr>
{% endfor %}
It looks great and I can see every value in the table clearly
I need to update these values every 5 seconds and for that, I am using jquery (using ajax just to get the updated value and put in the values below e.g var task_status_cpu_percent = data["task status cpu percent"];(list))
for(var i = 0; i< task_status_pid.length; i++){
$("#task-pid").text(task_status_pid[i]);
$("#task-memory-percent").text(task_status_memory_percent[i]);
$("#task-name").text(task_status_name[i]);
$("#task-cpu-percent").text(task_status_cpu_percent[i]);
}
task_status_pid is a list, in fact, all of the task_status are lists in the same length but when the jquery code accrues it doesn't do anything! I tried using replaceWith and that didn't go well
what happened is that all the values were on the first tab.
what do I need to do in order to go through all of the values in task-pd task-name etc' like it is on the loop ({% for (s_pid, s_name, s_cpu_percent, s_memory_percent) in zip(pid, name, cpu_percent, memory_percent)%})
You need to use class or add a counter to the ID. IDs MUST be unique
So EITHER
{% set count = namespace(value=0) %}
{% for (s_pid, s_name, s_cpu_percent, s_memory_percent) in zip(pid, name, cpu_percent, memory_percent)%}
<tr>
<td id="task-pid{{count.value}}">{{s_pid}}</td>
<td id="task-name{{count.value}}">{{s_name}}</td>
<td id="task-cpu-percent{{count.value}}">{{s_cpu_percent}}</td>
<td id="task-memory-percent{{count.value}}">{{s_memory_percent}}</td>
</tr>
{% set count.value = count.value + 1 %}
{% endfor %}
and then
$("#task-pid"+i).text(task_status_pid[i]);
OR (recommended)
const $tasks = $(".task-pid");
for(var i = 0; i< task_status_pid.length; i++){
$tasks.eq(i).text(task_status_pid[i]);
....
}
using <td class="task-pid" etc
I am trying to populate a table in django template, but I want to compare cell values, one of them is javascript variable and another is django template variable. Is it possible to compare them without converting django variables to javascript variables? or is there a quick work around?
{% for x in price_data %}
<script>
counter++
var VALUE =document.getElementById("price_table").rows[0].cells.item(counter).innerHTML;
</script>
{% if x.room_scan == i and x.checkin == VALUE %}
I want to check if x.checkin is equals to VALUE.
Thanks.
You can do something like this. Code I used to create the table (as I don't have original table)
<table id="price_table">
<tr>
{% for x in range %}
<td>{{ x }}</td>
{% endfor %}
</tr>
</table>
I passed these variables to view
{
'range': range(1,5),
'x_room_scan': 2
}
and inside the template (I reduced the code a bit to simplify it)
<script>
var counter = 0;
{% for x in range %}
counter++;
var value =document.getElementById("price_table").rows[0].cells.item(counter).innerHTML;
if({{ x_room_scan }} == value) {
console.log(value);
}
{% endfor %}
</script>
I know there are many questions already posted for the same issue but none of the solutions work in my case.
On calling a web service I get JSON response. In this JSON, there are around 2000+ objects from which I need to display data on the table. I want to display all (2000+) records in the table and Yes, I cannot limit or paginate, need to display it on a single page (I know it's stupid but it's the business requirement). I don't need sorting or searching.
Data transfer is about 2MB and the request completes in about 2-4 secs approx. but it takes around 10-15 secs to data render on the page.
Now, what I am looking for is either speed ng-repeat binding things up (if possible) or display the data as soon as I receive it and keep on adding it until all rows are displayed.
Check out the code below :
HTML
<table class="table table-bordered table-striped cf">
<thead style="color: #333;">
<tr>
<td>Asset Name</td>
<td>Date/ Time</td>
<td>Location</td>
<td>Ignition</td>
<td>Speed</td>
<td>Heading</td>
<td>Direction</td>
</tr>
</thead>
<tbody>
<tr ng-repeat="cols in tableData">
<td>{{ cols.aN }}</td>
<td>{{ cols.dT }}</td>
<td>{{ cols.Lat }}, {{ cols.Lon }}</td>
<td>{{ cols.I }}</td>
<td>{{ cols.S }}</td>
<td>{{ cols.H }}</td>
<td>{{ cols.D }}</td>
</tr>
</tbody>
</table>
JS
var ignition_text = '';
var lat = '';
var lon = '';
for (var i = 0; i < data.length; i++) {
if (data[i].ignition = 1) {
ignition_text = "On";
} else {
ignition_text = "Off";
}
$scope.$apply(function() {
$scope.tableData.push({
aN: name,
dT: data[i].eventUTCTime,
Lat: data[i].latitudeDegrees,
Lon: data[i].longitudeDegrees,
I: ignition_text,
S: data[i].speedMPH,
H: data[i].longitudeDegrees,
D: data[i].latitudeDegrees
});
});
}
Thanks in advance!
You probably wont need $scope.$apply at all. And even if you need it, you should only use it once you pushed all data to the table. Otherwise, every added entry will force an digest-cycle. Just build your array and assign the finished array to the scope-variable. Then angular will only build the table once.
Depending on the nature of your variable name you may be able to eliminate the array building as well and just use the data you are downloading. Apart from nameyou just use that data anyway.
Here is a plunk that has a similar data size but loads much faster http://plnkr.co/edit/I4rN1ZMaR3e1mbcsJ9Ka. If you were to make a quick plunk I could use your data and edit your code but from the looks you just need the main assignment to the scope without the apply for the data and add a track by to the ng-repeat. SN: You would want to manipulate your data inside the for loop then do the assignment to the scope.
for (var i = 0; i < data.length; i++) {
if (data[i].ignition = 1) {
ignition_text = "On";
} else {
ignition_text = "Off";
}
}
$scope.tableData=data;
JS
$http.get("largeData.json").then(function(response) {
vm.test = response.data;
});
HTML
<tbody>
<tr ng-repeat="(key, value) in main.test track by $index ">
<td>{{ value.ask }}</td>
<td>{{ value.bid }}</td>
<td>{{ value.volume_btc }}, {{ value.volume_percent }}</td>
<td>{{ value.last }}</td>
<td>{{ value.timestamp }}</td>
</tr>
</tbody>