How can I set colspan depending on hidden-xs a column using Bootstrap? - html-table

I have a table with a dynamic row which I hide one of its columns using bootstrap hidden-xs. The next row which is footer is using colspan.
I wonder if it's possible to set the number of colspan depending on `screen-size (hidden-xs).
<table class="table table-bordered">
{% for product in products %}
<tr>
<td class="text-left hidden-xs">{{ product.name }}</td>
<td class="text-left">{{ product.model }}</td>
<td>{% for option in product.option %}
{% if option.type != 'file' %}
<div><small><span class="hidden-xs">{{ option.name }}: </span>{{ option.value }}</small></div>
{% else %}
<div><small><span class="hidden-xs">{{ option.name }}: </span>{{ option.value }}</small></div>
{% endif %}
{% endfor %}</td>
<td class="text-right">{{ product.quantity }}</td>
<td class="text-right">{{ product.price }}</td>
<td class="text-right">{{ product.total }}</td>
</tr>
{% endfor %}
{% for total in totals %}
<tr>
<td colspan="5" class="text-right">{{ total.title }}</td>
<td class="text-right">{{ total.text }}</td>
</tr>
{% endfor %}
<tbody>
UPDATE
For now such an approach came to my mind:
<tr class="hidden-xs">
<td colspan="5" class="text-right">{{ total.title }}</td>
<td class="text-right">{{ total.text }}</td>
</tr>
<tr class="hidden-xl hidden-lg hidden-sm">
<td colspan="4" class="text-right">{{ total.title }}</td>
<td class="text-right">{{ total.text }}</td>
</tr>
Is there any better solution?

First of all, Bootstrap 4 doesn't have a hidden-xs class. In fact, it doesn't have any type of hidden-* utility. Unless you defined such utilities yourself, you should probably use d-none d-sm-table-cell classes instead of hidden-xs.
Documented here
To your question, you can't set colspan responsively on a <td> using CSS.
The proper way to do it is to use JavaScript, along these lines:
const isXs = window.matchMedia('(max-width: 576px)')
const changeColspans = () =>
[...document.querySelectorAll('.variable-colspan')].forEach((cell) => {
cell.setAttribute('colspan', isXs.matches ? 2 : 4)
})
changeColspans()
window.addEventListener('resize', changeColspans)
where 2 and 4 are the colspan values you want to set to colspan when isXs.matches is true/false. You'll need to add variable-colspan class to each cell you want to change.
If you really want to stay away from a JS solution, for whatever reason, you could work around it, by creating a separate <td> for each case and using Bootstrap's display utilities (linked above) to display the appropriate one on the current responsiveness interval. Generic example:
<td coslapn="2" class="d-sm-none">I render on xs only</td>
<td colspan="4" class="d-none d-sm-table-cell">I render on sm and above</td>
The advantage of using JS here is that you don't need to swap DOM elements which has the potential to lose events bound on the element or generate rendering performance issues, on larger tables. These issues can be addressed, of course, but it's better not to have them in the first place.
JS can also easily handle multiple cases, whereas with the CSS workaround you need a separate element for each case.

Related

Using v-for in a table

I have a table is populated with some info and I would like to format the table like the picture
Unfortunately the excel sheet which I have no control over is formatted so:
I want any row that has only a Equipment type to span whole row. All other rows should appear as normal table row.
I am using following vue template:
<table>
<caption>
SHS Scrap Table
</caption>
<thead>
<tr>
<th>Make</th>
<th>Model #</th>
<th>Bar Code</th>
<th>Serial #</th>
<th>Location</th>
<th>Condition</th>
</tr>
</thead>
<tbody v-for="item in scrapDataEmptyRowsRemoved" :key="item">
<tr v-if="item['Equipment Type']">
<td class="equipt-type" colspan="6">
Equipment Type - {{ item["Equipment Type"] }}
</td>
</tr>
<tr v-else>
<td>{{ item["Make"] }}</td>
<td>{{ item["Model #"] }}</td>
<td>{{ item["Bar Code"] }}</td>
<td>{{ item["Serial #"] }}</td>
<td>{{ item["Location"] }}</td>
<td>{{ item["Condition"] }}</td>
</tr>
</tbody>
</table>
The only problem is that looking in Devtools I see that every row has a Tbody which is not semantically correct. Any idea's on how to correct this. If I use a container around the v-if v-else all formatting breaks down.Thanks...
Update the only problem is Vite is objecting to moving :key attribute to the v-else:
I dont what other unique key they want.
Update II - Ok apparently if I use different object keys Vite is ok with that ie :key="item['Equipment Type'] and on v-else :key="item['Make']. Does that seem correct?
You can move the v-for in a template tag, that won't be rendered in the DOM.
<tbody>
<template v-for="item in scrapDataEmptyRowsRemoved" :key="item">
<tr v-if="item['Equipment Type']">
<td class="equipt-type" colspan="6">
Equipment Type - {{ item["Equipment Type"] }}
</td>
</tr>
<tr v-else>
<td>{{ item["Make"] }}</td>
<td>{{ item["Model #"] }}</td>
<td>{{ item["Bar Code"] }}</td>
<td>{{ item["Serial #"] }}</td>
<td>{{ item["Location"] }}</td>
<td>{{ item["Condition"] }}</td>
</tr>
</template>
</tbody>

How to connect/link input with Ng Zorro Table (Create search table)

I wish to create a search feature in my NG ZORRO table by linking/connect nz-input with nz-table. Is is possible to do so? Or is there any other methods to do so?
<uic-page>
<p>user-details works!</p>
<nz-input-group [nzSuffix]="suffixIconSearch">
<input type="text" nz-input placeholder="input search text" />
</nz-input-group>
<ng-template #suffixIconSearch>
<i nz-icon nzType="search"></i>
</ng-template>
<nz-table #basicTable [nzData]="listOfData">
<thead>
<tr>
<th>Name</th>
<th>Age</th>
<th>Address</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let data of basicTable.data">
<td>{{ data.name }}</td>
<td>{{ data.age }}</td>
<td>{{ data.address }}</td>
<td>
<a>Action δΈ€ {{ data.name }}</a>
<nz-divider nzType="vertical"></nz-divider>
<a>Delete</a>
</td>
</tr>
</tbody>
</nz-table>
Thanks.
This should work fine
Just make an event on the input and change the data based on that
also make sure you make copy of the data (if the search is client-side) to avoid lose the data

Displaying data using v-for with VueJS

Looping data from an array. The problem is that the loop creates 3 empty tables, guessing it's because im calling item. 3 times. If I want the data from the array without Vue creating empty tables, how should I display the data? Been trying to use {{users.firstname}} without the v-for loop but doesn't seem to work.
<table v-for="item in users">
<tbody>
<tr>
<td>{{ item.username }}</td>
</tr>
<tr>
<td>{{ item.firstname }}</td>
</tr>
<tr>
<td>{{ item.lastname }}</td>
</tr>
</tbody>
</table>
Solved using <template v-for="item in users" v-if="item.username && item.firstname && item.lastname">. No extra elements are printed out.
If you want to create 3 rows per user, use a <template> tag to group them, and use v-for on that template:
<table>
<tbody>
<template v-for="item in users">
<tr>
<td>{{ item.username }}</td>
</tr>
<tr>
<td>{{ item.firstname }}</td>
</tr>
<tr>
<td>{{ item.lastname }}</td>
</tr>
</template>
</tbody>
</table>
Have a look at this fiddle for an example: https://jsfiddle.net/nfa43bhq/

Using rowspan while iterating

Let's say I have the following two lists:
names = ['Josh', 'Brad', 'Jordan']
favorite_colors = [['blue', 'red'], ['purple', 'gold', 'yellow'], ['green', 'pink']]
That is to say, Josh's favorite colors are blue and red, Brad's are purple and gold, etc.
I'm passing this data to a jinja2 template via flask and I'm looking to throw it all in a table. I want the table to look like so: https://jsfiddle.net/46qqfef5/
As you can see, I'm using the rowspan attribute to group name and color. However, when I try to iterate over the data using the jinja2 code below the <td rowspan="2"> tag appears in EVERY row (and I need it to only appear the first time a new name occurs).
jinja2:
<div class="table-responsive">
<table class="table table-bordered table-hover">
<thead>
<tr>
<th>Name</th>
<th>Favorite Color</th>
</tr>
</thead>
<tbody>
{% for name_index in range(names | count) %}
{% for color_index in range(favorite_colors[name_index] | count %}
<tr>
<td rowspan="{{ favorite_colors[name_index] | count }}">{{ names[name_index] }}</td>
<td>{{ favorite_colors[name_index][color_index] }}</td>
</tr>
{% endfor %}
{% endfor %}
</tbody>
</table>
<div
If I remove rowspan={{ ... }} from the jinja2 code above I get the following table but that looks pretty awful to me: https://jsfiddle.net/46qqfef5/3/
I need a way to print the name cell for only the first occurrence of a new name.
You can use special loop variables for checking if current loop is first. In your case loop.first can be used:
<table>
<thead>
<tr>
<th>Name</th>
<th>Favorite Color</th>
</tr>
</thead>
<tbody>
{% for name_index in range(names | count) %}
{% for color in favorite_colors[name_index] %}
<tr>
{% if loop.first %}
<td rowspan="{{ favorite_colors[name_index] | count }}">
{{ names[name_index] }}
</td>
{% endif %}
<td>{{ color }}</td>
</tr>
{% endfor %}
{% endfor %}
</tbody>
</table>

Simple. How to right aligned a table?? What Am I missing?

I have search extensively and have not had any luck. I have try some of the right aligned coding and I appear to just make things worse. I try to research and fix the problem without asking question but here I am. Basically I need my table to right aligned. The table that has "invoice, date, total, payments, and balance remaining". I have attached a photo also. The code I have for just the table is below:
<div class="col-xs-4">
<table class="table">
<tbody>
<tr>
<td>
<strong>Invoice</strong>
</td>
<td class="text-right">
{{ job.job_number }}
</td>
</tr>
<tr>
<td>
<strong>Date</strong>
</td>
<td class="text-right">
{% if job.scheduled_on %}
{{ job.scheduled_on | date: "%m/%d/%y" }}
{% endif %}
</td>
</tr>
<tr>
<td>
<strong>Total</strong>
</td>
<td class="text-right">
{{ job.total | currency }}
</td>
</tr>
<tr>
<td>
<strong>Payments</strong>
</td>
<td class="text-right">
{{ job.total_applied_payments | currency }}
</td>
</tr>
<tr>
<td>
<strong>Balance Remaining</strong>
</td>
<td class="text-right">
{{ job.balance | currency }}
</td>
</tr>
</tbody>
</table>
</div><!-- .col-xs-4 -->
</div><!-- .row -->
photo