select child element jQuery - javascript

I have a table structured like this:
<table>
<tbody>
for loop here
<tr>
<td>Item X Attribute 1</td>
<td>Item X Attribute 2</td>
<td><button name="test" onclick="display_variants()">Hide my kids</button></td>
</tr>
<tr>
<tbody class="variants_info">
<tr>
<td>Item X Variant 1</td>
<td>Item X Variant 2</td>
</tr>
</tbody>
</tr>
endfor loop
</tbody>
</table>
So that structure repeats Y amount of times.
I'm trying to make a script that hides the tbody.variants of the row selected.
What I have so far is this:
<script>
function display_variant(){
if($('.variants_info').is(":visible")){
$('.variants_info').hide();
}
else{
$('.variants_info').show();
}
}
</script>
but this hides the variants from ALL the rows.
Is there a way to select the childs of the specific row? Also how can I start with the tbody.variants hidden? (Start as in when I visit the page).
Edit: At the moment is looking closely to this:
Update:
I've managed to change the structure to this:
<table>
for loop
<tbody>
<tr>
<td>image for el 1</td>
<td>attr for el 1</td>
<td><button type='button' name='test'>Click Me</button></td>
</tr>
for loop
<tr class='variants_info'>
<td>variant1 for el 1</td>
<td>variant2 for el 1</td>
</tr>
endfor
</tbody>
endfor
</table>
Update 2: The actual code is this one:
<table class="pure-table pure-table-bordered">
<tbody>
{% for product in collection.products %}
{% if product.available %}
<tr class="{% cycle 'pure-table-odd', '' %}">
<td>
<img src="{{ product.featured_image.src | product_img_url: 'thumb' }}" alt="{{ product.featured_image.alt | escape }}" />
</td>
<td>{{ product.title }}</td>
<td style="text-align:right">
<button type="button" name="click_me">Click Me</button>
</td>
</tr>
{% for variant in product.variants %}
<tr>
<td>{{variant.title}}</td>
<td>{{variant.price | money }}</td>
</tr>
{% endfor %}
{% endif %}
{% endfor %}
</tbody>
</table>
<script>
$("td button").click(function(){
$(this).closest('tr').next().toggle();
})
</script>
I still can't get the JS to work.. =/ Current one is only hiding the first variant( Instead of all the variants for the clicked button )

I would suggest to mark the rows that contain the products with a class name, e.g. "product", like this:
<tr class="product {% cycle 'pure-table-odd', '' %}">
<td>
<img src="{{ product.featured_image.src | product_img_url: 'thumb' }}"
alt="{{ product.featured_image.alt | escape }}" />
</td>
<td>{{ product.title }}</td>
<td style="text-align:right">
<button type="button" name="click_me">Click Me</button>
</td>
</tr>
You would not add that class to the rows that have the variants.
Then in your JavaScript use the nextUntil method to match all next variant rows (which do not have the "product" class) until, but excluding, the next product row, and apply the toggle() method to all these:
$("td button").click(function(){
$(this).closest('tr').nextUntil('.product').toggle();
});
Alternative structure 1
Instead of a single table, you could create nested tables, one for each product, containing the variants. It would look somewhat like this:
<table class="pure-table pure-table-bordered">
<tbody>
{% for product in collection.products %}
{% if product.available %}
<tr class="{% cycle 'pure-table-odd', '' %}">
<td>
<img src="{{ product.featured_image.src | product_img_url: 'thumb' }}"
alt="{{ product.featured_image.alt | escape }}" />
</td>
<td>{{ product.title }}</td>
<td style="text-align:right">
<button type="button" name="click_me">Click Me</button>
</td>
</tr>
<tr>
<table class="some other class specific for variants">
<tbody>
{% for variant in product.variants %}
<tr>
<td>{{variant.title}}</td>
<td>{{variant.price | money }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</tr>
{% endif %}
{% endfor %}
</tbody>
</table>
This has advantages and disadvantages. The main disadvantage is that the columns of these sub-tables are not aligned with the columns in the main table. But it depends on what you want...
The JavaScript code would then have to be like you had it originally:
$("td button").click(function(){
$(this).closest('tr').next().toggle();
});
Alternative structure 2
You could also wrap each "section" (consisting of one product row and the variant rows that belong to it) with a tbody tag. Although not commonly done, this is allowed as stated on MDN:
Note that unlike the <thead>, <tfoot>, and <caption> elements however, multiple <tbody> elements are permitted (if consecutive), allowing the data-rows in long tables to be divided into different sections, each separately formatted as needed.
This is different from your original HTML, where you had tbody elements as children of tr elements, which is invalid HTML.
It would look like this:
<table class="pure-table pure-table-bordered">
{% for product in collection.products %}
{% if product.available %}
<tbody>
<tr class="{% cycle 'pure-table-odd', '' %}">
<td>
<img src="{{ product.featured_image.src | product_img_url: 'thumb' }}"
alt="{{ product.featured_image.alt | escape }}" />
</td>
<td>{{ product.title }}</td>
<td style="text-align:right">
<button type="button" name="click_me">Click Me</button>
</td>
</tr>
{% for variant in product.variants %}
<tr>
<td>{{variant.title}}</td>
<td>{{variant.price | money }}</td>
</tr>
{% endfor %}
</tbody>
{% endif %}
{% endfor %}
</table>
You can then use the nextAll() method to hide the variant rows, because they are delimited by the tbody wrapper from the next product row:
$("td button").click(function(){
$(this).closest('tr').nextAll().toggle();
});
Initially hiding the variant rows
If you want the variants all to be hidden at first, then add the following attribute to those rows in the HTML code:
<tr style="display:hidden">
You would of course not do this for the product rows. Also, you might want to define a CSS class for this (e.g. tr.hidden { display:hidden; } instead of using style.
The jQuery toggle() method will override this style when showing, and restore it again when hiding.

Your HTML is not valid so you can change that and then use this DEMO
$("td button").click(function() {
$(this).closest('tr').next().toggle();
})

try this one :-
$("td button").click(function() {
$(this).closest('tr').nextUntil("tbody").toggle();
});
the jsfiddle demo link is :- https://jsfiddle.net/Lg0wyt9u/776/

Related

Dropdown filtering objects in django template using javascript

I have a table that shows details about all the assets. I want the records in the table to be filtered on the basis of different attributes of the table. For now I have tried to create a filter on currentOwner field using JavaScript, but it is not working.
Here is the html file:
{% extends "assets/base.html" %}
{% block content %}
<div class="container">
<legend class="border-bottom mb-4">Hello {{ request.user }}</legend>
</br>
<table class="table" id="admin-asset-table">
<tr>
<th>Asset ID</th>
<th>Asset Type</th>
<th>Asset Name</th>
<th>Brand</th>
<th>Is Active</th>
<th>
<select id="searchddl" onclick="searchOwner();">
<option disabled="true" selected>-- Current Owner --</option>
{% for user in users %}
<option value="{{asset.currentOwner}}">
{{user.username}}
</option>
{% endfor %}
</select>
</th>
<!-- <th>Current Owner</th> -->
</tr>
{% for asset in assets %}
<tr>
<td>{{ asset.id }}</td>
<td>{{ asset.asset_type }}</td>
<td>{{ asset.asset_name }}</td>
<td>{{ asset.brand }}</td>
<td>{{ asset.isActive }}</td>
<td>{{ asset.currentOwner }}</td>
</tr>
{% endfor %}
</table>
</div>
<script type="text/javascript">
function searchOwner()
{
var input,table,tr,td,filter,i;
input=document.getElementById("searchddl");
filter=input.value.toUpperCase();
table=document.getElementById("admin-asset-table");
tr=table.getElementsByTagName("tr");
for(i=0; i<tr.length; i++)
{
td=tr[i].getElementsByTagName("td")[3];
if(td)
{
displaydata=td.innerText;
if(displaydata.toUpperCase().indexOf(filter)>-1)
{
tr[i].style.display="";
}
else
{
tr[i].style.display="none";
}
}
}
}
</script>
{% endblock content%}
Please let me know what is wrong with this. Also let me know if there is any possible way to apply multiple filters of this kind.

Jinja table, when column == value then add div to specific column

I have a flask app with a jinja table, one of the columns has the value = 1 when that row meets a criteria.
For every row that a 1 is present in that column i would like to replace it with a circle, for example:
How would I add it to my jinja table?
<table>
<thead>
<tr>
{% for col in column_names %}
<th>
{{col}}
</th>
{% endfor %}
</tr>
</thead>
<tbody>
{% for row in row_data %}
<tr>
{% for col, row_ in zip(column_names, row) %}
{% if loop.index == 1 %}
<td>
IF {{ row[16] }} == 1 then <div class="circle" style="float: left;">LB</div>
else ''
end
{{row_}}</td>
{% else %}
<td>{{row_}}</td>
{% endif %}
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
HTML/CSS code of div i want to appear in that cell
.circle
{
width:20px;
height:20px;
border-radius:10px;
font-size:8px;
color:#fff;
line-height:20px;
text-align:center;
background:#000
}
<div class="circle" style="float: left;">LB</div>
Solution
Try the following.
The one-line if-else statement in jinja2 looks like this:
{{ OUTPUT_WHEN_TRUE if condition else OUTPUT_WHEN_FLASE }}
So, in your case, the code within for each <td></td> (where loop.index == 1 over the inner loop) will look like this:
{{ '<div class="circle" style="float: left;">LB</div>' if row[16] == 1 else '' }} {{ row_ }}
Code
<table>
<thead>
<tr>
{% for col in column_names %}
<th>
{{col}}
</th>
{% endfor %}
</tr>
</thead>
<tbody>
{% for row in row_data %}
{% set row_loop = loop %}
<tr>
{% for col, row_ in zip(column_names, row) %}
{% set col_loop = loop %}
{# Choose which loop: row or col you are referring to #}
{% if col_loop.index == 1 %}
<td>
{{ '<div class="circle" style="float: left;">LB</div>' if row[16] == 1 else '' }} {{ row_ }}
</td>
{% else %}
<td>{{ row_ }}</td>
{% endif %}
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
References
Get loop index of outer loop
Jinja Docs - Accessing the parent Loop
Jinja shorthand conditional: one-line if-else

Pass value from clickable table row into Python using Flask/Jquery

So, I am new to Python and Flask, and building an aplication which shows a list of portfolios in a table. Now, I made these rows clickable using js/Jquery. What I would like to acchieve however, is that the value of the second column of the clicked row (portfolio_id) is somehow returned to Python. The idea is that after selecting a portfolio from the list, a new screen with the details of that specific portfolio appears, so Python needs to know which portfolio to load. I do manage to include a href/link into the click event, so the new screen appears, but I cant figure out how to get the value from my table into my Python code.... Below the Flask code:
{% block main %}
<h2>Portfolio List</h2>
<ul>
<table style="width:100%">
<tr>
<th>Relationship Nbr </th>
<th>Portfolio Nbr </th>
<th>Strategy </th>
<th>Portfolios </th>
<th>Last Rebalancing </th>
</tr>
{% for portfolio in portfolios %}
<tr class='clickable-row' data-href="{{ url_for('portfolio') }}" method = POST>
<td>{{portfolio.rel_nbr }} </td>
<td>{{portfolio.portfolio_id}}</td>
<td>{{portfolio.strategy_name}} </td>
<td>{{portfolio.security_list}} </td>
<td>{{portfolio.last_rebalance}} </td>
</tr>
{% endfor %}
</table>
</ul>
{% endblock %}
The jquery code I use is as follows:
src="jquery-3.2.1.min-js">
jQuery(document).ready(function($) {
$(".clickable-row").click(function() {
window.location = $(this).data("href");
});
});
Any ideas how this can be done?
Txs!!
Bart
Your code is working fine for me. I have just changed place for jquery script.
Try to place your jquery script in proper place. I think this is the only reason your code is not working.
jQuery(document).ready(function($) {
$(".clickable-row").click(function() {
alert($(this).data("href"));
window.location = $(this).data("href");
});
});
{% block main %}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<h2>Portfolio List</h2>
<ul>
<table style="width:100%">
<tr>
<th>Relationship Nbr </th>
<th>Portfolio Nbr </th>
<th>Strategy </th>
<th>Portfolios </th>
<th>Last Rebalancing </th>
</tr>
{% for portfolio in portfolios %}
<tr class='clickable-row' data-href="{{ url_for('portfolio') }}" method = POST>
<td>{{portfolio.rel_nbr }} </td>
<td>{{portfolio.portfolio_id}}</td>
<td>{{portfolio.strategy_name}} </td>
<td>{{portfolio.security_list}} </td>
<td>{{portfolio.last_rebalance}} </td>
</tr>
{% endfor %}
</table>
</ul>
{% endblock %}

The lines breaks in my rows when viewing in PDF. (When adding minus symbol)

I have a problem when i View my html page in PDF-form. The problem is that when the number values are to big then it breaks the line between the minus symbol and values.
Here is an example of the hmtl page, it works perfect
enter image description here
Then when i convert it to a PDF it looks like this:
enter image description here
Here i Render my page to a full html document:
def document_to_html_document(document):
"""
Renders the invoice to a full html document with <html>, <head>, and <body> tags.
"""
return render_to_string('invoice_print.html', {
'body': document_to_html(document),
'document': document,
'base_url': settings.SITE_BASE_URL
})
The code where i build the HTML string and converting it to a pdf:
def document_to_pdf(document, server_base_url, target=None):
# Build HTML string
html = document_to_html_document(document)
# Setup input and output files
html_file = tempfile.NamedTemporaryFile(suffix='.html')
html_file.write(document_to_html_document(document).encode())
target = target or tempfile.NamedTemporaryFile()
# Convert to pdf
command = 'xvfb-run wkhtmltopdf --footer-right "[page]/[topage]"{s} {o}'.format(
s=html_file.name,
o=target.name
)
s = subprocess.Popen(command, shell=True)
s.communicate()
# Return pdf bytes
target.seek(0)
return target.read()
This is my hmtl code where i add the "body":
<html>
<head>
<title>MOSEK-{{ document }}</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<!-- JQuery -->
<script src="{{ base_url }}static/assets/vendor/jquery-1.11.1.js"></script>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="{{ base_url }}static/assets/vendor/bootstrap-3.1.1-dist/css/bootstrap.min.css">
<!-- Optional theme -->
<link rel="stylesheet" href="{{ base_url }}static/assets/vendor/bootstrap-3.1.1-dist/css/bootstrap-theme.css">
<!-- Latest compiled and minified JavaScript -->
<script src="{{ base_url }}static/assets/vendor/bootstrap-3.1.1-dist/js/bootstrap.min.js"></script>
<style>
body {
width: 950px;
}
</style>
</head>
<body>
<div>
<div class="container">
{{ body|safe }}
</div>
</div>
</body>
I have no idea how to solve it, any help would be appreciated :)
This is the content of the Invoice_body:
<div class="row">
<div class="col-xs-12">
<table class="invoice-lines">
<thead>
<tr class="underline overline">
<th>No.</th>
<th>Part ID / Description</th>
<th class="nowrap fr sec-column">Quantity</th>
<th class="nowrap fr sec-column">List price</th>
<th class="nowrap fr sec-column">Unit price</th>
<th class="nowrap fr sec-column">Total</th>
</tr>
</thead>
<tbody>
{# We want the border-bottom of the last line to be darker. #}
{# In order to find this last line, we first need to determine #}
{# if there are custom items. If there are, then the last line #}
{# will be a custom item, since they are printed last. If not, #}
{# then we need to find the last product line. #}
{% for line in lines %}
{% with lines|next:forloop.counter0 as next_line %}
<tr class="line{% if not citems and not next_line %} last-line{% endif %}">
<td>{{ line.line }}</td>
<td>
{% if line.objs.0.product.name %}
{{ line.objs.0.product.name }}<br />
{% else %}
{{ line.objs.0.serial.product.name }}-{% if line.objs.0.back == 1 %}BACK{% endif %}MAIN<br />
{% endif %}
{% if line.objs.0.back and line.objs.0.back_description != '' %}
{{ line.objs.0.back_description }}<br />
{% elif line.objs.0.back == False and line.objs.0.description != '' %}
{{ line.objs.0.description }}<br />
{% else %}
{{ line.objs.0.description }}<br />
{% endif %}
{% if line.objs.0.start %}
Period: {{ line.objs.0.start }} - {{ line.objs.0.end }}<br />
{% endif %}
Serial(s): {{ line.list }}
</td>
<td class="nowrap fr sec-column">{{ line.qty }}</td>
<td class="nowrap fr sec-column">{{ line.objs.0.price|floatformat:2 }}</td>
<td class="nowrap fr sec-column">
{{ line.objs.0.subtotal|floatformat:2 }}
{% if line.discount %}<br>({{ line.discount }}% dis.){% endif %}
</td>
<td class="nowrap fr sec-column">{{ line.rowtotal|floatformat:2 }}</td>
</tr>
{% endwith %}
{% endfor %}
{% for citem in citems %}
{% with citems|next:forloop.counter0 as next_citem %}
<tr class="line{% if not next_citem %} last-line{% endif %}">
<td>{{ citem.line }}</td>
<td>
{{ citem.obj.name }}
{% if citem.obj.agreement %}
<br>Agreement: {{ citem.obj.agreement }}
{% endif %}
</td>
<td class="sec-column"> </td>
<td class="fr sec-column">{{ citem.rowtotal|floatformat:2 }}</td>
<td class="fr sec-column">{{ citem.rowtotal|floatformat:2 }}</td>
<td class="fr sec-column">{{ citem.rowtotal|floatformat:2 }}</td>
</tr>
{% endwith %}
{% endfor %}
<tr class="sum-line" id="subtotal-line">
<th colspan="4" class="fr">Subtotal</th>
<th> </th>
<td class="fr sec-column">{{ inv.subtotal|floatformat:2 }}</td>
</tr>
{% for vat, lines, message, total, rate in vats %}
<tr class="sum-line">
<td colspan="4" class="fr">
<span class="nowrap">Line {{ lines }} : </span>
{{ message }}
<span class="nowrap"> ({{ rate }}% VAT)</span>
</td>
<td class="fr sec-column">{{ total }}</td>
<th> </th>
</tr>
{% endfor %}
<tr class="sum-line">
<th colspan="4" class="fr">VAT total</th>
<th> </th>
<td class="fr sec-column">{{ inv.vat|floatformat:2 }}</td>
</tr>
<tr class="sum-line">
<th colspan="4" class="fr">Total ({{ inv.currency }})</th>
<th> </th>
<td class="fr grand-total overline sec-column">{{ inv.total|floatformat:2 }}</td>
</tr>
</tbody>
</table>
</div>
</div>
add the flag zoom to the export command:
command= xvfb-run wkhtmltopdf --zoom 1.5 --footer-right
The solution from Eliethesaiyan:
in the command= xvfb-run wkhtmltopdf --zoom 1.5 --footer-right

window.open is having issue with firefox

I am using window.open method to open a new webpage in myhtml. but when I am running it in Firefox it is reloading the same page. But it is working in Chrome and Safari. Here is my html and javascript snippet.I am using Python Flask framework with Jinja template. I also tried using location.replace instead of window.open
</div>
<form name="items">
<script type="text/javascript" language="javascript">
function getdetails(name){
window.open("/details?name="+name,"_self")
}
</script>
<table id="main" align="center" class="table table-striped table-bordered" >
<thead>
<tr>
<th> <strong> SNo </strong></th>
<th> <strong> name </strong></th>
<th> <strong> item </strong></th>
<th> <strong> Total numbers </strong></th>
<th> <strong> size </strong></th>
</tr>
</thead>
{% set count = 1 %}
<tbody id="tablebody">
{% for i in rows %}
{% for name,values in i.iteritems() %}
<tr>
<td style="text-align: center"> {{ count }}</td>
<td> {{ name }} </td>
{% for j in values %}
<td> {{ j }} </td>
{% endfor %}
</tr>
{% endfor %}
{% set count = count + 1 %}
{% endfor %}
</tbody>
</table>
</form>
</div>
Try using window.location.href instead of window.open, location.href is a property and not a method so you'd have to call it differently, but it does work like a page redirect, although i'd try to figure out whats going wrong with window.open - it is the more 'correct' way.
window.location.href = 'http://www.google.com';
Since your questions was a bit unclear, if you're trying to make the page open in a new tab, change _self to _blank in the window.open method.
window.open("/details?name="+name,"_blank");

Categories

Resources