Conditionally changing the formatting of cells in a loop-generated table - javascript

My django app generates a table on the basis of the python dictionary "participants". To do that, it uses the HTML code below, which features a loop that run through all the *elements* of "participants". The table is generated without any problems.
Now I want to conditionally change the background color of the column with the value "balance", depending on whether that value is > 0, < 0, or = 0. To that purpose, I have inserted javascript at the bottom of the HTML body. But this has no effect whatsoever. How can the code be fixed?
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Participants</title>
</head>
<body>
<h1>Participants</h1>
<table id="participants_table" border="1">
{% for x in participants %}
<tr>
<td>{{ x.firstName }}</td>
<td>{{ x.lastName }}</td>
<td class="balance">{{ x.balance }}</td>
</tr>
{% endfor %}
</table>
<script>
var balance = document.getElementById('participants_table').getElementsByClassName('balance');
if (balance.innerHTML > 0){
balance.style.backgroundColor='#003F87';
} else if (balance.innerHTML < 0) {
balance.style.backgroundColor='#0033H7';
} else {
balance.style.backgroundColor='#0093H7';
}
</script>
</body>
</html>

Theoretically this should work.
<td style=background-color: "{% if x.balance > 0 %}#003F87{% elif
x.balance < 0 %}#0033H7 {%else%)#0093H7{% endif %}">{{ x.balance
}}</td>
So I am using inline styling(not recommended) and conditionally rendering the bg color. If you're using something like Bootstrap, then it may be cleaner like this:
<td class="{% if x.balance > 0 %}bg-primary{% elif x.balance < 0
%}bg-warning{%else%)bg-secondary{% endif %}>{{ x.balance }}</td>

Related

search box for all the pages after Django pagination of table

I have developed a web app using Django.
I have created a table pagination.
how could I create a search input for all the data in all the pages of table?
view.py
def Browse_and_adopt(request):
Title_list = Title.objects.all()
page = request.GET.get('page', 1)
paginator = Paginator(Title_list, 10)
try:
Titles = paginator.page(page)
except PageNotAnInteger:
Titles = paginator.page(1)
except EmptyPage:
Titles = paginator.page(paginator.num_pages)
page_obj = paginator.get_page(page)
return render(request, 'bms/inbox/Browse_and_adopt.html', {'Titles': Titles, 'page_obj': page_obj})
Browse_and_adopt.html
<table id="myTable">
<thead>
<tr>
<th>Title</th>
</tr>
</thead>
<tbody>
% for book in page_obj %}
<tr>
<td>{{ book.title }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="pagination">
<span class="step-links">
{% if page_obj.has_previous %}
« first
previous
{% endif %}
<span class="current">
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
</span>
{% if page_obj.has_next %}
next
last »
{% endif %}
</span>
</div>
Now only the first page shows, how to create a search bar for all the data in the table?
The view does not know whick object you are looking for.
There is two ways to do so.
In the frontend end where you write a JS callback event listener that filter all the supplied table data. " not optimal ''
Or you can create a custom view that recieve the object pk via post request and return the filtered result e.g url :
urlpatterns = [
path('update/<int:pk>/', updateViewSet.as_view()),
]

create table with dynamic rows and columns with django html template

I'm trying to create a table with dynamic rows and columns based on the results list with django html template. The number of records and header number could change. I am using two for loops to get the number of rows and the column number. I'm having a hard time trying to output the actual values in the table. The idea was to "index" from the second for loop and applying it to "each" of first loop. I know that the syntax is definitely wrong, but is something that django can do? If not, is there any suggestions that I can research on how to implement this? Thanks!!
list = [
{'header_a': foo1, 'header_b': foo2, 'header_c': foo3},
{'header_a': foo1, 'header_b': foo2, 'header_c': foo3},
{'header_a': foo3, 'header_b': foo3, 'header_c': foo3},
{'header_a': foo4, 'header_b': foo4, 'header_c': foo4},
]
Sample Table
header_a | header_b | header_c
foo1 | foo1 | foo1
foo2 | foo2 | foo2
foo3 | foo3 | foo3
foo4 | foo4 | foo4
or
list_2 = [
{'header_c': c_foo1, 'header_d': d_foo1},
{'header_c': c_foo2, 'header_d': d_foo2},
]
Sample Table 2
header_c | header_d
c_foo1 | d_foo1
c_foo2 | d_foo2
<table>
<thead>
<tr>
{% for index in list.0 %}
<th>{{ index }}</th>
{% endfor %}
</tr>
</thead>
<tbody>
{% for each in list %}
<tr>
{% for index in a %}
<td>{{ each.{{index}} }}</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
Well, as you have a list of dicionaries in that schema, this is how you can iterate it inside the template:
<table>
<thead>
<tr>
{% for item in list %}
{% if forloop.first %}
{% for h in item %}
<th>{{ h }}</th>
{% endfor %}
{% endif%}
{% endfor %}
</tr>
</thead>
<tbody>
{% for item in list %}
<tr>
{% for key,value in item.items %}
<td>{{ value}}</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
Assuming you have the same keys in every dictionary (column headers or fields as you name them), you first iterate only the first dicionary to get its keys, then, you iterate again the values for rows...
Not the most efficient solution tho, it would be great if you can rewrite the way you create that list.
Hope it helps and please confirm if it works
maybe you should check out django tables? It's a pretty known tool to creating powerful tables with django. You can create them based on a model, but you can also simply pass the data directly to them. I also once used it to create a dynamic table. It takes all the job from the template and add it to the view where things are easier to manipulate.

Flask infinite scroll loading data fail

I wrote a infinite scroll with jquery and flask, but Can't load all the data out.
(I want to load 10 items from list "vocs" per time.)
jinja2:
<tbody id="xxx">
{% for _ in range(0,10) %}
<tr>
{% for i in vocs.pop(0) %}
<td>{{ i }}</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
jquery:
<script>
$(window).scroll(function () {
if ($(window).scrollTop() >= $(document).height() - $(window).height() - 10) {
var c = '';
{% for _ in range(0,10) %}
c += '<tr>';
{% for i in vocs.pop(0) %}
c += ('<td>' + '{{ i }}' + '</td>');
{% endfor %}
c += '</tr>';
{% endfor %}
$('#xxx').append(c);
}
});
</script>
Each time when scroll to bottom, I got this result:
1~10
==> scroll to bottom
11~20
==> scroll to bottom
11~20
==> scroll to bottom
11~20
.
.
.
It seams that "vocs" pop out isn't in my anticipation. (It's weird that pop seams not working. Every time I trigger event, it still began from 11~20)
I know I must misunderstood something, but I don't know why.
EDIT 1:
Reclaim my question for more specific details.
I got "vocs" from server at first, and it contains items from 1~100.
when I first scroll to bottom, it works well.
1~10
==> scroll to bottom
11~20
But when I scrool to bottom again, the scenario isn't in my anticipation.
==> scroll to bottom
11~20
I think I've got all the "vocs" I want at first time(it contains 1~100), and I don't need to get it again from client.
Jinja2: Templates seems correct. I checked the code with a simple range, it load properly for me when i scroll down. Perhaps you should check vocs. The issue should be with that.
<table>
<tbody id="xxx">
{% for _ in range(0,10) %}
<tr>
{% for i in range(1,6) %}
<td>{{ _ }} - {{ i }}<br/><br/><br/><br/><br/></td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
JQuery:
<script>
$(window).scroll(function () {
if ($(window).scrollTop() >= $(document).height() - $(window).height() - 10) {
var c = '';
{% for _ in range(0,10) %}
c += '<tr>';
{% for i in range(1,6) %}
c += ('<td>' + '{{ _ }}{{ i }}' + '</td>');
{% endfor %}
c += '</tr>';
{% endfor %}
$('#xxx').append(c);
}
});
</script>

Hide table header if there is no row

I have a table with patients in which, for each row of table I can remove the row or do other operations, so when I remove all the rows I want my table header to be hidden or removed.
<table id ="results-table" class="table table-strip">
<thead>
<tr>
<th>Emri</th>
<th>Mbiemri</th>
<th>Numri personal</th>
<th>Vendi i lindjes</th>
<th>Data e diagnozës së parë</th>
<th>Data e raportimit</th>
<th>Mjeku raportues</th>
<th>Veprimet</th>
</tr>
</thead>
{% if patient_docs and patient_docs.collection.count() > 0 %}
<tbody id="patient-list">
{% for patient_doc in patient_docs %}
<tr>
{% if patient_doc.patient is defined %}
<td>{{ patient_doc.patient.emri }}</td>
<td>{{ patient_doc.patient.mbiemri }}</td>
<td>{{ patient_doc.patient.numri_personal }}</td>
<td>{{ patient_doc.patient.vendi_lindjes }}</td>{% endif %}
<td>{% if patient_doc.diagnosis is defined %}{{ patient_doc.diagnosis.data_diagnozes_se_pare }}{% endif %}</td>
<td>{% if patient_doc.treatment is defined %}{{ data_e_raportimit }}{% endif %}</td>
<td>{% if patient_doc.treatment is defined %}{{ patient_doc.treatment.mjeku_raportues }}{% endif %}</td>
</tr>
{% endfor %}
</tbody>
{% endif %}
</table>
So how can I do that using jQuery, so that if there is no row hide the header and and show a message there is no patient registered?
You can put the line
{% if patient_docs and patient_docs.collection.count() > 0 %}
before the "thead"
OR
with jquery in a document.ready, you can check the lenght
if ($('#results-table > tbody > tr').length == 0){
$('#results-table > thead > th').css('display','none');
}
everytime u remove a row u can count the number of rows left using
var rowCount = $('#myTable tbody tr').length;
if rowcount goes to 0 then just hide the table using .hide()
in your add and remove functions you can add method like renderBody which will be hide or show your tbody part:
function addRow() {
...
renderBody();
}
function removeRow() {
...
renderBody();
}
function renderBody() {
var $tbody = $('#patient-list');
if (patient_docs && patient_docs.collection.count() > 0) {
$tbody.show();
}
else {
$tbody.hide();
}
}
Noticed you actually want to basically hide the entire table (not just the header) and show a message saying that no patients are registered.
Easy way to do this would be to create a function, check if rows exist, if they do then hide message, show table, otherwise do the opposite
var $msg = $('#msgDivId');
function showMsgOnEmptyTable(target, msg){
var $target = $(target);
if( $target.find('tr') ){
$target.show( );
$msg.hide();
} else {
$target.hide();
$msg.show();
}
}
in html
<div id="msgDivId">
No Patients Registered
</div>
<table id="targetTable"> ... table stuff goes here ... </table>
And when ever you make changes to the table call
showMsgOnEmptyTable('#targetTable');

How to make a table tr into a link?

Here is my current solution:
<tr onclick="window.location = '/info/{{ match.login.id }}/'">
<td>{% if match.image %}<img src="{{ match.image|crop:'64x64' }}" alt="Match Avatar" />{% endif %}</td>
<td>{{ match.team_name }}</td>
<td>{{ model|distance_to:match }} {{ model.display_distance }}</td>
<td>{% for expertise in match.expertise_list %}
<span{% if expertise in model.expertise_list %} class="match"{% endif %}>{{ expertise }}</span><br />
{% endfor %}</td>
<td>{% if model|active_connection_with:match %}{{ model|status_with:match }}{% else %}Connect{% endif %}</td>
But the thing that is wrong with this is that I want to be able to right click and copy link etc. How can i accomplish this?
Right-click to copy a link only works on the A tag. You'd have to write your own right-click hander.
It's invalid markup (and doesn't work on browsers) when you have HTML elements between table elements (tr, td, th).
If your table cells are too complicated to mark up as a link, what you can do is have an invisible <a> element that covers each <td> that you want to link:
<table>
<tr>
<td>
Google
</td>
<td>
Yahoo
</td>
</tr>
</table>
td {
position: relative;
}
.overlay {
background-color: transparent;
position: absolute;
width: 100%;
height: 100%;
}
Demo: http://jsfiddle.net/waitinforatrain/puTbj/1/
The only downside is that users can't select the text under it.

Categories

Resources