Converting HTML tables to bootstrap columns - Responsive Design - javascript

I have been working on an old product that we have, that currently uses HTML tables to display its content. In this world of responsiveness, I would like to make that responsive. After reading up online, I believe it might end up being a lot of work to rework the whole website, however, I am trying to find a solution that would convert any table into columns based on divs that contain bootstrap columns. A very example of this is given here for a login page:JsFiddle
I don't have access to the source of the fields, however, I can add elements (append/prepend) using jQuery. I can also add CSS styles.
Could someone help me out in this approach, please?
<table></table>
.
.
.
<div class="container">
<div class="row">
<div class="col-md-3">
</div>
</div>
</div>
Cheers.

It might be hard to flawlessly convert any given table to bootstrap columns. Consider that bootstrap columns only allow for up to 12 columns and a table may have more than that.
This function will convert a table to BS rows/cols, but it assumes the number of table rows is evenly divisible by 12 (if not, you'll have to adjust it to your own needs).
/**
* Convert a table to bootstrap columns
* #param table DOMElement
*/
function makeBSCols(table){
var html = ["<div class='container'>"];
$(table).find('tr').each(function(){
var $td = $(this).find('td').length ? $(this).find('td') : $(this).find('th');
// get the column width
if($td.length > 12) return alert("too many columns");
var cls = Math.floor(12/$td.length);
if(cls!==(12/$td.length)) return alert("invalid column count");
html.push("<div class='row'>");
$td.each(function(){
html.push('<div class="col-sm-'+cls+'">'+$(this).html()+'</div>');
});
html.push('</div>');
});
html.push('</div>');
$(table).replaceWith(html.join(''));
}
Example: makeBSCols(document.getElementById('myTable')) (Fiddle)
For a more flexible solution, (assuming you're actually displaying tabular data) you might consider just using BS tables rather than BS cols/rows. This one will just add BS styles to your table and put it in a .table-responsive div which helps with responsiveness.
/**
* Convert a regular table to bootstrap table
* #param table DOMElement
*/
function makeBSTable(otable){
var table = $(otable).clone(); console.log(table);
table.addClass("table-hover table-bordered table-striped table");
var div = $('<div class="table-responsive" />');
$(otable).replaceWith(div);
div.append(table);
}
Example: makeBSTable(document.getElementById('myTable')) (Fiddle)

To the OP: You need to rewrite your tables in entire project
As per your requirement you don't want to rework any of the tables that are built and Also you want to convert existing tables to responsive div's.
Firstly to give a solution that can work on your entire project it is very important that all the tables in your site follow same standard in its struture. Which I see from the login page its very random at the moment.
Even if you write a solution that can work on the screen you provided (login screen) I am not sure if that will be sufficient for your entire site. Tables in your screen are nested to the core. You never know what all might break if you take this aproach.
So my suggestion is.. What was done is done.. Previous developers used to use only tables to structure there pages, But the world has changed to responsiveness. And it will change in the next few years too. We never know. So its high time for you to rewrite all the pages into new HTML structure and be upgraded to latest possible code.
To general public: who want to change table to divs according to devices
Quick Check: Working fiddle (resize the result screen to see the effect)
As far as I understand the requirement you want to show a table in medium and large devices, But when the user is on small device or resize the screen to small then you want to display it in different manner, More like a div structure.
I have a solution using inbuilt bootstrap classes.
Solution:
Create both your table (that you show in medium and large devices) and the other HTML structure (that you want to show in small devices).
Use bootstrap provided Helper Classe to toggle the display of table and the other section according to the viewport.
Here is the snap from the Doc's and a TestCase
So with the above given details all you need is ..
// the tables are visible only on medium and large devices
<table class="visible-md-block visible-lg-block">
//..your table structure
</table>
// This section is only visible in small and extra small devices
<div class="visible-xs-block visible-sm-block">
//The table data represented in a div structure.
//Each row can be structured as sections with header as label and row data as value.
</div>
Disadvantages:
With this approach you will end up with additional HTML if user is in any device Or never resizes the screen.
Advantages:
This doesn't require you to keep tack of when the screen is resized so that you build the new section. Which also means you dont need Jquery.
This doesnt reuire you to find out which device is the user on.
Working is slick as its only CSS
Hope this helps!!

i think you would have to rewrite your whole html if the site is based on html tables.
If you use tables just as "normal" tables you could just add class="table to your table
furthermore you could wrap your table inside an div with class="table-responsive"
e.g.:
<div class="table-responsive">
<table class="table">
...
</table>
</div>
there also some further styles available: table-hover table-striped ...
you can find some samples here: http://getbootstrap.com/css/#tables

I don't think this is the "nicest" form to solve your problem, but if you can only use CSS and jQuery I think you can just div every part of the table data, use $(...).hide() to make it invisible and then use $(...).html() to place that content into the Bootstrap's div's.

I think you're right that a complete refactor might cost a lot of work. However I would really consider a more let's call it hybrid solution: Why not pick some components and refactor them nicely. The old product you have will improve significantly, but just not 100% in the first step. For the parts which cannot be refactored right now, make a nifty plan. The solutions mentioned by others address your question perfectly, but I think you'll be stuck with a unmaintainable product in the end. And nobody will benefit from such a product, right?

Bootstrap is divided columns and rows that are responsive to all device try this
use this type of responsive design.
<!DOCTYPE html>
<html>
<head>
<title>test</title>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
<div class="container">
<div class="row">
<div class="col-lg-offser-2 col-lg-5">
<form>
<div class="form-group">
<input type="text" name="username" class="form-control" placeholder="Username">
</div>
<div class="form-group">
<input type="password" name="pass" class="form-control" placeholder="Password">
</div>
<div class="form-group">
<button class="btn btn-success">Login</button>
</div>
</form>
</div>
</div>
</div>
</body>
</html>

You could use jQuery to pull information and simply add it to the table you have. I use the tags then the headers as and inside it I use normal and tags. Works for me. I use jQuery to pull data and add to the table. It's quite easy to do.
Something useful for responsive bootstrap pages could be using the table code below and placing it in a where you create a column such as:
<div class="container">
<div class="row">
<div class="col-md-4"> </div>
<div class="col-md-4"> /*You can place the table in here*/ </div>
<div class="col-md-4"> </div>
</div>
</div>
Here is the sample table code:
<table>
<thead>
<tr>
<th>header 1</th>
<th>header 2 </th>
</tr>
</thead>
<tbody>
/*You could pull and add the data in here with <tr> and <td> using jQuery*/
</tbody>
</table>

Tables are for tabular data. If that is what is in the tables, it would be best to keep them as tables. This is for semantic reasons as well as accessibility (and compliance with Section 508 in the USA). You can use the .table-responsive class to help make it look better on mobile and not break anything.
There are other things which make tables more responsive such as stackable and tablesaw to name a few.
Even if you convert to bootstrap's rows and columns, you have a set 12-column grid, if they content of the table does not fix in there nicely, it will have a bad user experience.

UPDATE:
It was not clear from the original post that the author needed to deal with deeply nested tables. I have updated his JsFiddle accordingly.
Here's some jQuery code I wrote a while back which converts tables into bootstrap rows and columns on the fly. It assumes that the table is symmetrical, no colspan or rowspan attributes.
One of the primary concerns when converting a table to a bootstrap layout is to handle the header row properly. This jQuery code will do that provided that all of the header cells are using the th tag. You could easily just assume anything on the first row was a header by replacing find('th') with find('th,td').
Lastly, it is important to preserve the attributes of the original table, such as id's, classes and onclick events. Any events that were added programmatically may need to be reapplied.
$('table:not(:has(table))').each(function() {
debugger;
var rowSelector = 'tr';
var attributes = $.map(this.attributes,function(a,i) {
return a.name+'="'+a.value+'"';
}).join(' ');
// handle collapsible headers
var $headers = $('tr:first', this).find('th');
var columns = $('tr:first',this).find('th,td').length;
if ($headers.length > 0) {
$headers.closest('tr').addClass('row visible-sm visible-md visible-lg');
$headers.addClass('form-group col-sm-' + Math.floor(12 / $headers.length)).wrapInner('<label></label>');
rowSelector = 'tr:not(:first)';
}
// add classes to each data row
$(rowSelector, this).addClass('row').each(function() {
$('td,th', this)
.addClass('form-group col-sm-' + Math.floor(12 / columns))
.filter(function() {
return $headers.length > 1;
})
.each(function (i) {
// add collapsible headers to each row
$(this).prepend('<label class="visible-xs">' + $($headers[i]).html() + '</label>');
});
});
// convert input elements to bootstrap styled controls
$(':input', this).addClass('form-control').css('width', '');
var divs = '<div class="container"><div '+attributes+'>'+$(this).html()
.replace(/<\/{0,1}tbody>/gi, '')
.replace(/<(tr|td|th)/gi, '<div')
.replace(/<\/(tr|td|th)/gi, '</div')+'</div></div>';
$(this).replaceWith(divs);
});
$('table').each(function() {
var rewrite = $(this).html()
.replace(/<(\/{0,1})table/gi, '<$1div')
.replace(/<\/{0,1}tbody>/gi, '')
.replace(/<(\/{0,1})(tr|td|th)/gi, '<$1div');
$(this).replaceWith( rewrite );
});
Given this sample table
<table>
<tr><th>First Name</th><th>Last Name</th><th>Address</th><th>City</th><th>State</th><th>Zip Code</th></tr>
<tr><td>Jake</td><td>Elwood</td><td>1060 W Addison St</td><td>Chicago</td><td>IL</td><td>60613</td></tr>
<tr><td>John</td><td>Wayne</td><td>18601 Airport Way</td><td>Santa Ana</td><td>CA</td><td>92707</td></tr>
</table>
Results in the following bootstrap markup:
<div class="container">
<div class="row visible-md visible-lg">
<div class="form-group col-md-2">
<label>First Name</label>
</div>
<div class="form-group col-md-2">
<label>Last Name</label>
</div>
<div class="form-group col-md-2">
<label>Address</label>
</div>
<div class="form-group col-md-2">
<label>City</label>
</div>
<div class="form-group col-md-2">
<label>State</label>
</div>
<div class="form-group col-md-2">
<label>Zip Code</label>
</div>
</div>
<div class="row">
<div class="form-group col-md-2">
<label class="visible-xs visible-sm">First Name</label>
Jake
</div>
<div class="form-group col-md-2">
<label class="visible-xs visible-sm">Last Name</label>
Elwood
</div>
<div class="form-group col-md-2">
<label class="visible-xs visible-sm">Address</label>
1060 W Addison St
</div>
<div class="form-group col-md-2">
<label class="visible-xs visible-sm">City</label>
Chicago
</div>
<div class="form-group col-md-2">
<label class="visible-xs visible-sm">State</label>
IL
</div>
<div class="form-group col-md-2">
<label class="visible-xs visible-sm">Zip Code</label>
60613
</div>
</div>
<div class="row">
<div class="form-group col-md-2">
<label class="visible-xs visible-sm">First Name</label>
John
</div>
<div class="form-group col-md-2">
<label class="visible-xs visible-sm">Last Name</label>
Wayne
</div>
<div class="form-group col-md-2">
<label class="visible-xs visible-sm">Address</label>
18601 Airport Way
</div>
<div class="form-group col-md-2">
<label class="visible-xs visible-sm">City</label>
Santa Ana
</div>
<div class="form-group col-md-2">
<label class="visible-xs visible-sm">State</label>
CA
</div>
<div class="form-group col-md-2">
<label class="visible-xs visible-sm">Zip Code</label>
92707
</div>
</div>
</div>

var tablesYouWant = document.querySelectorAll("yourSelection"); //A selection of elements
for(var i = 0; i < tablesYouWantl i++){
i.class += "classNames"; //Add Bootstrap classes to the elements
}

you should need to add a class like this using bootstrap class table -responsive
<div class="table-responsive">
<table class="table">
...
</table>
</div>

Related

How to fix row alignment issue in bootstrap/Javascript

Github repo (https://github.com/teke85/Luxury_living/tree/add-home-page)
In my bootstrap project I successfully managed to retrieve data dynamically from a javascript object. I noticed that the last row is not aligned correctly. how do i fix this or what could have caused the misalignment? Please note, The issue wasn't there before I fetched the data dynamically using Javascript.
If you are using the newest version, you can do something like this:
<div class="container">
<div class="row">
<div class="col">
Content for column 1
</div>
<div class="col">
Content for column 2
</div>
</div>
</div>

How to dynamically size distinct row columns in React to be the same

I have a table structure which is made out of distinct blocks which cannot be brought into the same block, such as this - only much larger.
The structure of this ideally needs to stay the same.
<div class="dynamicList">
<div class="header">
<div class="item">col1</div>
<div class="item">col2</div>
</div>
<div class="row">
<div class="item">Learn JavaScript</div>
<div class="item">test message</div>
</div>
<div class="row">
<div class="item">Build something awesome</div>
<div class="item">medium message</div>
</div>
</div>
I want a way to be able to dynamically size the columns in the row to auto fit to the text so that the largest text column width is used for all the others of the same column. On the top is how it looks, at the bottom is how I want it to look.
I was hoping I could get away with just using CSS for this, however I feel I might need some JavaScript too. I am using React, so thought about using useRef hook, but didn't know how well this would perform with a really large table.
What is the best way to calculate this width and then use it across all columns of the same index?
Here is a JS fiddle showing the problem.
https://jsfiddle.net/og8kz3hp/65/

Dygraph will not display in Bootstrap card

I want to create a dygraph graph within the Bootstrap card body's second column (it just looks nice and clean). The div used by dygraph is graphdiv. I am using this.$refs.graphdiv to try to access it from within my vue script.
If I move the graphdiv <div> outside the card div then it works (see the comment). Why will the dygraph not work within the bootstrap card? Is it just one of those compatibility things one must log with the developer and wait for a fix?
<template>
<div>
<div class="card">
<div class="card-header">HEADER</div>
<div class="card-body">
<div class="row">
<div class="col-sm-3" style="width: 100%">
</div>
<div class="col-sm-9">
<div id="graphdiv" style="width: 100%" ref="graphdiv"></div>
</div>
</div>
</div>
</div>
</div>
<!--Comment: IF I PLACE IT HERE IT WORKS -->
</div>
</template>
Here is a reduced version of script:
<script>
import Dygraph from "dygraphs";
export default {
methods:{
plot_chart_series() {
//dataset = my data that I want to plot
const g = new Dygraph(this.$refs.graphdiv, dataset, {//options});
}
}
};
<script>
P.S.
My reason for using dygraph is I want to plot a dataset which is rather large (+-30000 datapoints), chart.js and Apexchart cannot manage that (I spent the better part of 3 hours trying to get them working). If there is no fix for my issue above, which other graphing libraries are there which are Vue friendly which can handle large datasets?
Workaround
I have managed to find a work-around and I can at least relatively narrow the problem and say that I do not think it is bootstrap.
<div class="card" ref="carder">
<div class="card-header">Graph</div>
<div class="card-body">
<div class="row">
<div class="col-sm-3">
<button>A_BUTTON</button>
</div>
<div class="col-sm-9">
<div ref="graphdiv" style="width: 100%"></div>
</div>
</div>
</div>
</div>
The above code snippet worked for me.
Changes to original:
I had an id="some_id" property in the containing parent div which I removed.
The entire card was wrapped in another div. This div had a ref="some_ref" property which I used from the Vue script to toggle the visibility. I did this with this.$refs.some_ref.style.display = "block"; & this.$refs.some_ref.style.display = "none";. I changed it to the following this.$refs.some_ref.style.visibility = "hidden"; and just changed the hidden to visible when I wanted to show the card. (It does not bother me that the hidden element still consumes space)
If I revert change number 2 above to the original then it fails to display. I still cannot explain it but it works.

Bootstrap: move div from one column to another, order counts for mobile devices

<div class="row">
<div class="col-lg-7">
<div>block1 with IDs and classes</div>
<div>block2 with IDs and classes</div>
</div>
<div class="col-lg-5">
<div>block3 with IDs and classes</div>
</div>
</div>
How to make it look like
block1
block3
block2
for mobile?
P.S. Of course I took a look at this questions before I asked mine:
SO: How do I change Bootstrap 3 column order on mobile layout?
It doesn't help.
Also, adding hidden-xs and visible-xs for two blocks of
<div>block2 with IDs and classes</div>
in different places doesn't help as IDs should be unique on the page.
Any suggestions? Thank you.
Example:
IMPORTANT: block 3 may be (and it is) taller (the height is bigger) than block1.
No need to use push/pull. Just think "mobile-first"..
<div class="row">
<div class="col-lg-7">
<div>block1</div>
</div>
<div class="col-lg-5">
<div>block3</div>
</div>
<div class="col-lg-7">
<div>block2</div>
</div>
</div>
http://www.codeply.com/go/jgvSJrMOnk
In the case where block 3 is taller than the other columns, create a special class to float it to the right on large screens..
#media (min-width:1200px) {
.pull-lg-right {
float:right;
}
}
Related:How do I change Bootstrap 3 div column order
Bootstrap with different order on mobile version (Bootstrap 4)
using push and pull properties of grid will do your work try this the push and pull will be only applied for small device
<div class="row">
<div class="col-lg-3">block1 with IDs and classes</div>
<div class="col-lg-3 col-sm-push-12">block2 with IDs and classes</div>
<div class="clearfix visible-lg-block"></div>
<div class="col-lg-6 col-sm-pull-12">block3 with IDs and classes</div>
</div>
Edit clearfix added for large device

Error with adding a background image using angular

I attempt to add a background image and use cover to let the browsed resize the image. However the image is very small and doesn't cover the whole background.
I am new to angular so I have a very small idea about how this works.
Also, the search bar isn't in the middle despite using zurb to manage spacing for me.
Here is what the page looks like
Here is the code:
<div >
<!-- Above fold -->
<div class="row">
<div id = "backgroundImage" class="large-12 small-12 columns" ng-style="{'background-image':'url(img/mainBackground.png)','background-size' : 'cover'}">
<!-- search bar -->
<div class="row">
<!--empty -->
<div class="large-3 small-3 columns">
</div>
<div class="large-6 small-6 columns">
<input type="text" id="searchBar" ng-style="{'width': '50%'}">
</div>
<!--empty -->
<div class="large-3 small-3 columns">
</div>
</div>
</div>
</div>
</div>
Adding on to #Marko's response, you are using Angular to style an attribute, but the styles you are providing are just static. Angular's ng-style attribute is intended to be used when you have dynamic styles that you want to apply at runtime based on a given condition. You aren't doing that. You're simply providing static styles that you want to be applied, inline. That's not really considered a best practice. It would be better to just use a static css stylesheet to do what you want.
That being said, the issue you're facing is purely a CSS one, not an angular-specific one. You just need to debug your style on your #backgroundImage div and you'll eliminate a lot of the complexity involved in using ng-style.
Here's a good tutorial on using full-page css background images: http://css-tricks.com/perfect-full-page-background-image/

Categories