I've a table in my project with a pseudo element to show which row is active. Having changed the table layout to fixed (which is needed), I started getting this strange layout where the active row would expand to take up the entire table, but the other rows would not:
I've replicated a similar problem here (codepen, snippet below) - it's not exactly the same (the active row doesn't extend), but I'm fairly sure any answer to this would help me fix my problem.
If you comment out the top active::after style you'll see the table return to its correct size.
Thanks
// TABLE DATA
const headers = ['Id', 'Name', 'Age', 'Location'];
const datasetOne = [
['1','John Jones','27','Swindon'],
['2', 'Pete Best', '23', 'Glasgow'],
['3', 'Jules West', '22', 'Exeter'],
['4', 'Kate Ford', '33', 'Fife'],
];
const datasetTwo = [
['5','Ruth Thompson','27','Birmingham'],
['6', 'Dominic Lawson', '23', 'Greater London'],
['7', 'Really really long name', '22', 'Manchester'],
['8', 'Nicholas Johnson', '33', 'Liverpool'],
];
const tableWrapper = document.querySelector('.table-wrapper');
const btn = document.querySelector('.btn');
let dataset = 1;
// Listeners
window.addEventListener('load', () => {
const data = formatData(datasetOne);
tableWrapper.insertAdjacentHTML('afterbegin', createTable(headers, data));
});
btn.addEventListener('click', () => {
// Remove the table
const table = document.querySelector('.table')
table.parentElement.removeChild(table);
// Create and insert a new table
let data;
if(dataset === 1) {
data = formatData(datasetTwo);
dataset = 2;
}
else if(dataset === 2) {
data = formatData(datasetOne);
dataset = 1;
}
tableWrapper.insertAdjacentHTML('afterbegin', createTable(headers, data));
})
// Functions to create the table
function formatData(data) {
const rows = data.map(row => {
return createHTMLRow(row);
});
return rows;
}
function createHTMLRow([id, name, age, location]) {
const row = [
`<td class="td--id">${id}</td>`,
`<td class="td--name">${name}</td>`,
`<td class="td--age">${age}</td>`,
`<td class="td--location">${location}</td>`
];
return row;
}
function createTable (theads, rows) {
const markup = `
<table class="table">
<thead class="thead">
<tr>
${theads.map((thead) => {
return `<th class="th--${thead.toLowerCase()}">${thead}</th>`;
}).join('')}
</tr>
</thead>
<tbody class="tbody">
${
rows.map((row, index) => {
return `<tr class="row ${index===0? 'active':''}">${row.map(col => {
return `${col}`
}).join('')}</tr>`
}).join('')
}
</tbody>
</table>
`;
return markup;
};
.active::after {
position: absolute;
content: '';
left: 0;
top: 0;
width: 2px;
height: 100%;
background-color: green;
}
* {
margin: 0;
box-sizing: border-box;
}
.container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 100%;
height: 100vh;
background-color: firebrick;
}
.table-wrapper {
display: flex;
background-color: white;
width: 30rem;
overflow: hidden;
}
.table {
display: table;
table-layout:fixed;
border-collapse: collapse;
overflow: hidden;
width: 100%;
}
th {
text-align: start;
padding: 1rem;
background-color: lemonchiffon;
border: 1px solid lightgrey;
}
.th--age, .th--id {
width: 4rem;
}
td {
padding: .5rem 1rem;
border: 1px solid lightgrey;
white-space: nowrap;
}
.td--name {
overflow: hidden;
text-overflow: ellipsis;
}
.row {
position: relative;
height: 2rem;
}
.btn {
padding: 1rem .8rem;
width: 7rem;
background-color: white;
margin-top: 2rem;
}
<div class="container">
<div class="table-wrapper"></div>
<div class="btn">Change Data</div>
</div>
**Edit:
#zer00ne's answer of using min-width did fix the row issue, but it's unfortunately caused other problems with text-overflow:ellipsis and column widths
If you click on the codepen, item 7 currently works and overflows as intended, and all the columns remain a fixed width, even if they aren't given a width in the css (extra space seems to be distributed evenly between them).
Adding min-width to the table, while fixing the row issue, unfortunately breaks this behaviour
Was hoping someone had any ideas on how I can keep the columns fixed (as the codepen currently behaves), while being able to add the pseudo element (or some way of achieving the same effect)
Thanks!
**Edit 2:
I guess I could just manually divide up the total table width between each of the columns, but that seems a bit fragile
Update
I believe that the pseudo-element .active::after may still be the culprit. It feels like a code smell, a quick google lead me to nowhere official, but from what little I found coincides with what I was saying before, It's basically an extra cell in a single row. Because it's a pseudo-element, it's not part of the DOM so if you put one in a place where other elements cannot exist (like being a child of a <tr>), you may get unexpected results.
So here's what I did, it looks good. Try to break it and let me know if it actually does:
I changed where .active is generated -- it is now assigned to the first <td> of the first <tr> within the <tbody>. <td> can hold just about anything and it looks exactly like it did as it was on the <tr>.
Figure I
function formatData(data) { // ↙️ Add the index parameter
const rows = data.map((row, idx) => {
return createHTMLRow(idx, row);
}); // ↖️ Pass it as the 1st parameter
//...
Figure II
// ↙️ Pass the index reference as 1st parameter
function createHTMLRow(i, [id, name, age, location]) {
const row = [
`<td class="td--id ${i===0? 'active':''}">${id}</td>`,
//... ↖️ Here's the index reference interpolated
Original Solution
Still good for most cases. The update is for an edge case.
The table is at width: 100% which doesn't guarantee 100% with fixed tables that have undefined <th> widths. Change table width:
table {min-width: 100%}
// TABLE DATA
const headers = ['Id', 'Name', 'Age', 'Location'];
const datasetOne = [
['1', 'John Jones', '27', 'Swindon'],
['2', 'Pete Best', '23', 'Glasgow'],
['3', 'Jules West', '22', 'Exeter'],
['4', 'Kate Ford', '33', 'Fife'],
];
const datasetTwo = [
['5', 'Ruth Thompson', '27', 'Birmingham'],
['6', 'Dominic Lawson', '23', 'Greater London'],
['7', 'XXXXXXXXXX XXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXX XXXXXXXXXXXXXX XXXXXXXx XXXXXX', '22', 'Manchester'],
['8', 'Nicholas Johnson', '33', 'Liverpool'],
];
const tableWrapper = document.querySelector('.table-wrapper');
const btn = document.querySelector('.btn');
let dataset = 1;
// Listeners
window.addEventListener('load', () => {
const data = formatData(datasetOne);
tableWrapper.insertAdjacentHTML('afterbegin', createTable(headers, data));
});
btn.addEventListener('click', () => {
// Remove the table
const table = document.querySelector('.table')
table.parentElement.removeChild(table);
// Create and insert a new table
let data;
if (dataset === 1) {
data = formatData(datasetTwo);
dataset = 2;
} else if (dataset === 2) {
data = formatData(datasetOne);
dataset = 1;
}
tableWrapper.insertAdjacentHTML('afterbegin', createTable(headers, data));
});
// Functions to create the table
function formatData(data) {
const rows = data.map((row, idx) => {
return createHTMLRow(idx, row);
});
return rows;
}
function createHTMLRow(i, [id, name, age, location]) {
const row = [
`<td class="td--id ${i===0? 'active':''}">${id}</td>`,
`<td class="td--name">${name}</td>`,
`<td class="td--age">${age}</td>`,
`<td class="td--location">${location}</td>`
];
return row;
}
function createTable(theads, rows) {
const markup = `
<table class="table">
<thead class="thead">
<tr>
${theads.map((thead) => {
return `<th class="th--${thead.toLowerCase()}">${thead}</th>`;
}).join('')}
</tr>
</thead>
<tbody class="tbody">
${
rows.map((row, index) => {
return `<tr class="row">${row.map(col => {
return `${col}`
}).join('')}</tr>`
}).join('')
}
</tbody>
</table>
`;
return markup;
};
.active::after {
position: absolute;
content: '';
left: 0;
top: 0;
width: 2px;
height: 100%;
background-color: green;
}
* {
margin: 0;
box-sizing: border-box;
}
.container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
background-color: firebrick;
}
.table-wrapper {
display: flex;
background-color: white;
width: 30rem;
overflow: hidden;
}
.table {
display: table;
table-layout: fixed;
border-collapse: collapse;
overflow: hidden;
width: 100%;
}
th {
text-align: start;
padding: 1rem;
background-color: lemonchiffon;
border: 1px solid lightgrey;
}
.th--age,
.th--id {
width: 4rem;
}
td {
padding: .5rem 1rem;
border: 1px solid lightgrey;
white-space: nowrap;
}
.td--name {
overflow: hidden;
text-overflow: ellipsis;
}
.row {
position: relative;
height: 2rem;
}
.btn {
padding: 1rem .8rem;
width: 7rem;
background-color: white;
margin-top: 2rem;
}
<div class="container">
<div class="table-wrapper"></div>
<div class="btn">Change Data</div>
</div>
I am trying to remove the padding from the cells inside my table. I have set it to not have padding in the relevant CSS selectors but not a success.
As you can see, there is padding on all of these cells.
I would like there to not be. I have tried various different padding settings and changing the vertical alignment makes no difference other than to move the text, the padding just goes from all at the bottom to spread between bottom and top.
Below is the code:
'use strict'
let table = document.getElementById("mainTable")
let rows = table.querySelectorAll("tbody tr")
let columns = table.querySelectorAll("#weeks th")
for (let row of rows) {
for (let o = 0; o<columns.length-1; o++) {
let cell = document.createElement("td")
cell.innerHTML=' '
cell.addEventListener("click", function() {
if (cell.getElementsByTagName("input")[0]) { return } //If cell currently has an input box
//
let oldValue = ""
if (cell.innerHTML !== " ") { //if cell has a saved value
oldValue = cell.innerHTML
}
cell.innerHTML = '<input type="text" class="cellInputs">'
//update input box with old value and focus it
cell.getElementsByTagName("input")[0].focus()
cell.getElementsByTagName("input")[0].value = oldValue
cell.getElementsByTagName("input")[0].addEventListener("keypress", function(e) {
if (e.keyCode === 13) {
cell.innerHTML=cell.getElementsByTagName("input")[0].value
e.preventDefault()
return true
}
})
cell.getElementsByTagName("input")[0].addEventListener("input", function(e) {
console.log(e)
let cellValue = cell.getElementsByTagName("input")[0].value
if (e.data === "." && (cellValue.split('.').length-1 > 1 || cellValue === ".")) {
console.log("stop")
cell.getElementsByTagName("input")[0].value = (cellValue).substring(0, cellValue.length - e.data.length)
}
if (isNaN(e.data) && e.data !==".") {
console.log("Stop")
cell.getElementsByTagName("input")[0].value = (cellValue).substring(0, cellValue.length - e.data.length)
}
//store value inputted into the actual cell
})
cell.getElementsByTagName("input")[0].addEventListener("paste", function(e) {
// clipboardData = e.clipboardData || window.clipboardData;
// pastedData = clipboardData.getData('Text');
let cellValue = cell.getElementsByTagName("input")[0].value
if (cellValue !== "") {
e.preventDefault()
return false
}
if (e.clipboardData.getData('text') === "." && (cellValue.split('.').length-1 > 1 || cellValue === ".")) {
e.preventDefault()
return false
}
if (isNaN(e.clipboardData.getData('text')) && e.clipboardData.getData('text') !==".") {
e.preventDefault()
return false
}
//store value inputted into the actual cell
})
cell.getElementsByTagName("input")[0].addEventListener("focusout", function() {
console.log(document.activeElement)
cell.innerHTML=cell.getElementsByTagName("input")[0].value
})
})
row.appendChild(cell)
}
}
*{
padding: 0;
margin: 0;
font-family: "Trebuchet MS", Times, serif;
box-sizing:border-box;
}
html{
background-color: #35454E;
overflow: hidden;
}
html *{
font-family: "Work Sans", Arial, sans-serif !important;
color: white !important;
}
table{
border-collapse: collapse;
border-spacing: 0px;
color:#35454E;
height:100%;
width:100%;
}
table, th{
border: 2px solid white;
padding:0;
}
th{
vertical-align:top;
font-size: 2.5vw;
}
td{
vertical-align:top;
box-sizing:border-box;
position: relative;
border: 2px solid white;
padding:0;
text-align: center;
font-size: 2.5vw;
padding:0;
}
.cellInputs{
position: absolute;
width:100%;
height:100%;
display: block;
top:0;
left:0;
border:none;
text-align: center;
background-color: #35454E;
word-wrap: break-word;
font-size: 2.5vw;
}
<html>
<head>
<link rel="stylesheet" type="text/css" href="MMS.css">
<title>Money Management</title>
</head>
<body>
<table id="mainTable">
<thead>
<tr>
<th>2019</th>
<th colspan="5">January</th>
</tr>
<tr id="weeks">
<th> </th>
<th>31/12/2018</th>
<th>07/01/2019</th>
<th>14/01/2019</th>
<th>21/01/2019</th>
<th>28/01/2019</th>
</tr>
</thead>
<tbody>
<tr>
<th>Balance</th>
</tr>
<tr>
<th>Pay</th>
</tr>
<tr>
<th> </th>
</tr>
<tr>
<th>Rent</th>
</tr>
<tr>
<th>Food</th>
</tr>
<tr>
<th> </th>
</tr>
<tr>
<th>Total</th>
</tr>
</tbody>
</table>
</body>
<script src="MMS.js"></script>
</html>
Remove height:100% from table .
I have been having issues with page breaks in tables. Thought I had a solution as it was working fine in this SO question:
Inserting a page break into of <table> in React app
This worked fine for a table with one column, but nowt that I am working with multiple columns, it is a mess.
Basically I have to include display: block to get the page break to work properly, but that makes it go from a well formatted table to this:
I have gone down the list in MDN just trying anything that might work.
https://developer.mozilla.org/en-US/docs/Web/CSS/display
Furthermore, page breaks are only working when on their own separate <tr> which is undesirable since it generates a blank page. Got this sorted out by moving the pagebreak to the <tr> instead of the <td>.
I haven't been able to resolve these issues; any suggestions on how to approach this problem?
Not sure how useful a JSFiddle will be given the printing issue, but here is the compiled HTML. I can never get JSFiddle working with React:
https://jsfiddle.net/5gz62d91/
Best would probably be the Github repo:
https://github.com/ishraqiyun77/page-breaks
Here is the code separately:
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import styles from '../assets/scss/app.scss';
class PageBreakIssues extends Component {
// Render the data points
renderDataPoint() {
let dataPoint = [];
for (let i = 1; i <= 3; i++) {
let num = (Math.random() * 100).toFixed(2);
dataPoint.push(
<td className='data-point' key={ i }>
{ num < 25 ? null : num }
</td>
)
}
return dataPoint;
}
// Start generating the row data
renderDataRow() {
let dataRow = [];
for (let i = 1; i <= 5; i++) {
dataRow.push(
<tr key={ i }>
<td className='data-name' colSpan='3' key={i}>Test - { i }</td>
{ this.renderDataPoint() }
</tr>
)
}
return dataRow;
}
// Start generating table sections with the section name
// COMMENT THIS OUT TO TRY WITOUT ADDING A BLANK ROW
renderSections() {
let sections = [];
for (let i = 1; i <= 10; i++) {
sections.push(
<tbody key={ i }>
<tr key={ i }>
<td colSpan='7' className='section-name' key={i} >
Section - { i }
</td>
</tr>
{ this.renderDataRow() }
{
i % 2 === 0
?
<tr className='pagebreak'>
<td colSpan='7'></td>
</tr>
:
null
}
</tbody>
)
}
return sections;
}
// Start generating table sections with the section name
// UNCOMMENT THIS SECTION TO TRY WITHOUT INSERT BLANK TR
// renderSections() {
// let sections = [];
// for (let i = 1; i <= 10; i++) {
// sections.push(
// <tbody key={i}>
// <tr key={i}>
// <td colSpan='7' className={ i % 2 === 0? 'section-name pagebreak' : 'section-name'} key={i} >
// Section - {i}
// </td>
// </tr>
// {this.renderDataRow()}
// </tbody>
// )
// }
// return sections;
// }
// Render the table with <th>
render() {
return (
<table>
<thead>
<tr>
<th colSpan='3'>Results</th>
<th>1</th>
<th>2</th>
<th>3</th>
</tr>
</thead>
{ this.renderSections() }
</table>
)
}
}
ReactDOM.render(<PageBreakIssues />, document.getElementById('app'));
#mixin borders {
border: 1px solid black;
}
%borders {
#include borders;
}
table {
border-spacing: 0;
th {
text-align: center;
}
tr {
th{
#extend %borders;
}
td {
#extend %borders;
&.data-name {
padding: 3px 100px 3px 3px;
}
&.data-point {
text-align: center;
padding: 3px 10px;
}
&.section-name {
background-color: #999;
}
}
}
}
#media print {
tr {
display: block;
}
.pagebreak {
break-before: always !important;
page-break-before: always !important;
page-break-inside: avoid !important;
}
}
I figure out an even more hard-coding method (so call perfectly solve your problem). I must said it is not elegant.
My method's main idea is changing tbody to display:block (as usual), but adding the .pagebreak to target tbody as well.
However, this method unattach tbody from the table and thus no longer align with thead. That's why I add a tr for printing thead, and remove the origin thead when print.
Added printing th, don't show in normal view
//Thead part, add a printing thead only shown in Print
//As originaly thead will has alloction problem
{ i % 2 === 1 ?
<tr className='printing-thead'>
<td colspan="3">Results</td>
<td>1</td>
<td>2</td>
<td>3</td>
</tr> : null
}
....
...
//Corrected Page break
</tbody>
<tbody class="pagebreak">
<tr>
<td colspan="7"></td>
</tr>
</tbody>
<tbody>
...
Corresponding CSS
table {
border-spacing: 0;
table-layout: fixed;
th {
text-align: center;
}
tr {
th {
#extend %borders;
}
td {
#extend %borders;
&.data-name {
padding: 3px 100px 3px 3px;
}
&.data-point {
text-align: center;
padding: 3px 10px;
}
&.section-name {
background-color: #999;
}
}
}
tr.printing-thead {
display: none;
}
}
#media print {
thead {
display: none;
}
tbody {
display: block;
tr.printing-thead {
display: contents;
font-weight: bold;
text-align: center;
}
}
.pagebreak {
height: 0px;
break-before: always !important;
page-break-before: always !important;
page-break-inside: avoid !important;
td {
display: none;
}
}
}
The JSfiddle.
And the react version
JSfiddle React Version
I am using Google Places autocomplete to select cities by name. Currently it displays only the city name and the country it belongs to, in the suggestions drop down.
I have checked and found that the "address_components" object, that gets populated when a city is selected, has additional attibutes like state/province and other parts of the address. So, it is clear that the Google's API provide additional information other than merely the city and country names.
What I am trying to achieve is, displaying a couple of those additional data in the suggestions dropdown.
Is there a way to do that?
(I have marked on the screenshot where I need to display the additional attributes)
Here is the code.
<script src="https://maps.googleapis.com/maps/api/js?key=API_KEY&libraries=places&callback=initAutocomplete&query=locality" async defer></script>
<script>
var searchBox;
function initAutocomplete() {
var options = {types: ['(cities)']};
var input = document.getElementById('placeAuto');
searchBox = new google.maps.places.Autocomplete(input);
searchBox.addListener('place_changed', fillInAddress);
}
function fillInAddress()
{
var place = searchBox.getPlace();
console.log(place);
}
</script>
As I commented already, you can do that by using the Autocomplete and Places services and the getPlacePredictions method, but I would not recommend this approach as it will make a high number of requests to the API (one for each result, each time a user types something in the address field).
View the snippet in full screen mode as it won't fit hereunder or check it on JSFiddle.
In this example I have added the place latitude and longitude in the autocomplete results.
var autocompleteService, placesService, results, map;
function initialize() {
results = document.getElementById('results');
var mapOptions = {
zoom: 5,
center: new google.maps.LatLng(50, 50)
};
map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
// Bind listener for address search
google.maps.event.addDomListener(document.getElementById('address'), 'input', function() {
results.style.display = 'block';
getPlacePredictions(document.getElementById('address').value);
});
// Show results when address field is focused (if not empty)
google.maps.event.addDomListener(document.getElementById('address'), 'focus', function() {
if (document.getElementById('address').value !== '') {
results.style.display = 'block';
getPlacePredictions(document.getElementById('address').value);
}
});
// Hide results when click occurs out of the results and inputs
google.maps.event.addDomListener(document, 'click', function(e) {
if ((e.target.parentElement.className !== 'pac-container') && (e.target.parentElement.className !== 'pac-item') && (e.target.tagName !== 'INPUT')) {
results.style.display = 'none';
}
});
autocompleteService = new google.maps.places.AutocompleteService();
placesService = new google.maps.places.PlacesService(map);
}
// Get place predictions
function getPlacePredictions(search) {
autocompleteService.getPlacePredictions({
input: search,
types: ['geocode']
}, callback);
}
// Place search callback
function callback(predictions, status) {
// Empty results container
results.innerHTML = '';
// Place service status error
if (status != google.maps.places.PlacesServiceStatus.OK) {
results.innerHTML = '<div class="pac-item pac-item-error">Your search returned no result. Status: ' + status + '</div>';
return;
}
// Build output for each prediction
for (var i = 0, prediction; prediction = predictions[i]; i++) {
// Get place details to inject more details in autocomplete results
placesService.getDetails({
placeId: prediction.place_id
}, function(place, serviceStatus) {
if (serviceStatus === google.maps.places.PlacesServiceStatus.OK) {
// Create a new result element
var div = document.createElement('div');
// Insert inner HTML
div.innerHTML += '<span class="pac-icon pac-icon-marker"></span>' + place.adr_address + '<div class="pac-item-details">Lat: ' + place.geometry.location.lat().toFixed(3) + ', Lng: ' + place.geometry.location.lng().toFixed(3) + '</div>';
div.className = 'pac-item';
// Bind a click event
div.onclick = function() {
var center = place.geometry.location;
var marker = new google.maps.Marker({
position: center,
map: map
});
map.setCenter(center);
}
// Append new element to results
results.appendChild(div);
}
});
}
}
google.maps.event.addDomListener(window, 'load', initialize);
body,
html {
font-family: Arial, sans-serif;
padding: 0;
margin: 0;
height: 100%;
}
#map-canvas {
height: 150px;
margin-bottom: 5px;
}
table {
border-collapse: collapse;
margin-left: 20px;
}
table td {
padding: 3px 5px;
}
label {
display: inline-block;
width: 160px;
font-size: 11px;
color: #777;
}
input {
border: 1px solid #ccc;
width: 170px;
padding: 3px 5px;
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-shadow: 0 2px 6px rgba(0, 0, 0, .1);
}
.pac-container {
background-color: #fff;
z-index: 1000;
border-radius: 2px;
font-size: 11px;
box-shadow: 0 2px 6px rgba(0, 0, 0, .3);
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
overflow: hidden;
width: 350px;
}
.pac-icon {
width: 15px;
height: 20px;
margin-right: 7px;
margin-top: 6px;
display: inline-block;
vertical-align: top;
background-image: url(https://maps.gstatic.com/mapfiles/api-3/images/autocomplete-icons.png);
background-size: 34px;
}
.pac-icon-marker {
background-position: -1px -161px;
}
.pac-item {
cursor: pointer;
padding: 0 4px;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
line-height: 30px;
vertical-align: middle;
text-align: left;
border-top: 1px solid #e6e6e6;
color: #999;
}
.pac-item:hover {
background-color: #efefef;
}
.pac-item-details {
color: lightblue;
padding-left: 22px;
}
.pac-item-error,
.pac-item-error:hover {
color: #aaa;
padding: 0 5px;
cursor: default;
background-color: #fff;
}
<div id="map-canvas"></div>
<table>
<tr>
<td>
<label for="address">Address:</label>
</td>
</tr>
<tr>
<td>
<input id="address" placeholder="Enter address" type="text" tabindex="1" />
</td>
</tr>
<tr>
<td colspan="2">
<div id="results" class="pac-container"></div>
</td>
</tr>
</table>
<script src="https://maps.googleapis.com/maps/api/js?libraries=places&key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk"></script>
Could someone help with this
http://jsfiddle.net/smilepak/8qRQB/4/
<div>
<table>
<tr>
<td class="headcol">Fiddle Options</td>
<td class="long">Created and maintained by Piotr and Oskar. Hosted by DigitalOcean. Special thanks to MooTools community.</td>
<td class="long">QWERTYUIOPASDFGHJKLZXCVBNM</td>
</tr>
<tr>
<td class="headcol">Legal, Credits and Links</td>
<td class="long" style="width:300px">QWERTYUIOPASDFGHJKLZXCVBNM</td>
<td class="long" style="width:300px">QWERTYUIOPASDFGHJKLZXCVBNM</td>
</tr>
<tr>
<td class="headcol">Ajax Requests</td>
<td class="long">QWERTYUIOPASDFGHJKLZXCVBNM</td>
<td class="long">QWERTYUIOPASDFGHJKLZXCVBNM</td>
</tr>
</table>
table {
border-collapse:separate;
border-top: 1px solid grey;
}
td {
margin:0;
border:1px solid grey;
border-top-width:0px;
}
div {
width: 600px;
overflow-x:scroll;
margin-left:10em;
overflow-y:visible;
padding-bottom:1px;
}
.headcol {
position:absolute;
width:10em;
left:0;
top:auto;
border-right: 1px none black;
border-top-width:1px;
/*only relevant for first row*/
margin-top:-3px;
/*compensate for top border*/
}
In firefox, the row border doesn't seem to line up. I want a table where the first column is frozen while the rest is scrollable. All rows are linked up to a single scroll bar so i can use in a loop via Razor view in MVC.
Thanks,
JSBIN: http://jsbin.com/IwisANaX/3/edit
CSS
...
.freeze td:nth-child(1),
.freeze th:nth-child(1) {
background: #ddd;
position: absolute;
width: 20px;
left: 0;
}
.freeze .bottomScroll {
overflow-x: hidden;
margin-left: 20px;
}
...
JS
var ns = $('.newScroll', table),
bs = $('.bottomScroll', table);
ns.scroll(function(){bs.scrollLeft(ns.scrollLeft());});
try using
.headcol {max-width: 10em}
also note that using
.headcol {position: absolute}
makes the cell not to align relatively to the document; that´s why it looks like that
I used this combination of JavaScript and CSS to solve the sticky column issue.
https://jsfiddle.net/5poxyje4/
JS (Commented Section has boostrap compatible code)
var $table = $('.table');
var $fixedColumn = $table.clone().insertBefore($table).addClass('fixed-column');
$fixedColumn.find('th:not(:first-child),td:not(:first-child),.excludeHeader').remove();
$fixedColumn.find('tr').each(function (i, elem) {
if(elem.rowSpan = "1"){
$(this).height($table.find('tr:eq(' + i + ')').height());
}
else{
for (x = i; x <= parseInt(elem.rowSpan); x++) {
var tempHeight = $(this).height() + $table.find('tr:eq(' + x + ')').height();
$(this).height(tempHeight);
}
}
});
//Comments for if you are using bootrap tables
//var $table = $('.table');
//var $fixedColumn = $table.clone().insertBefore($table).addClass('fixed-column');
//$fixedColumn.find('th:not(:first-child),td:not(:first-child),.excludeHeader').remove();
//$fixedColumn.find('tr').each(function (i, elem) {
// $fixedColumn.find('tr:eq(' + i + ') > th:first-child,tr:eq(' + i + ') > td:first-child').each(function (c, cell) {
// if (cell.rowSpan == "1") {
// $(this).height($table.find('tr:eq(' + i + '),tr:not(.excludeRow)').height());
// }
// else {
// for (x = 1; x < parseInt(cell.rowSpan) ; x++) {
// var tempHeight = $(this).height() + $table.find('tr:eq(' + x + ')').height();
// $(this).height(tempHeight);
// }
// }
// $(this).width($table.find('.stickyColumn').first().width());
// });
//});
CSS(Commented section has bootstrap compatible code in my Site.css)
.table-responsive>.fixed-column {
position: absolute;
display: inline-block;
width: auto;
border-right: 1px solid #ddd;
/* used z-index with bootstrap */
/*z-index: 9999;*/
}
/*This media query conflicted with my bootstrap container. I did not use it*/
#media(min-width:768px) {
.table-responsive>.fixed-column {
display: none;
}
}
/*Commented Section for if you are using bootstrap*/
/*.table-responsive>.fixed-column {
position: absolute;
display: inline-block;
width: auto;
border-right: 1px solid #ddd;
background-color:#ffffff;
}*/
This accounts for if a th or a td has a rowspan greater than 1 as well.