Change row order on printing using Bootstrap 3.3 - javascript

On a project im using Bootstrap 3.3 to show and graph some data, on screen it shows perfect but I also need to print a report using boostrap printing classes
Is there a way to Switch positions between 2 blocks ONLY WHEN PRINTING the page?
Thanks for your Help!!!

If you use flex-box on an element containing both, you could use the order property inside of a print media query to change it:
document.getElementById('simulate').addEventListener('click', function() {
document.getElementById('container').classList.toggle('print');
});
#container {
display: flex;
flex-direction: column;
}
#container > div {
width: 100%;
border: solid 1px;
}
#media print {
#container > div:first-child {
order: 2;
}
}
#container.print > div:first-child {
order: 2;
}
<div id="container">
<div>Top</div>
<div>Bottom</div>
</div>
<button id="simulate">Simulate Print</button>

Related

Why is chrome's print preview and printed view is different ? [HTML - CSS]

I have a demo angular project which has basic text and table inside as below.There is print button which is calling window.print() to make the page printed with applied styling.
printPage() {
window.print();
}
css:
#media print {
#page {
size: landscape;
margin: 0;
}
}
My demo project link:
https://stackblitz.com/edit/angular-qxlcna?file=src/print/print.component.ts
My aim is being able to print this table landscaped exactly how it seems on the web page without any crops.^
After print button clicked preview on chrome's print dialog looks great as below
Unfortunately after print, result is not as expected.As you can see there are crops from left and right sides of the paper.Although my other attempts to set margin:0 padding:0 stylings didn't work.How can I print exactly as same as what I'm seeing on HTML page?
I tried also this kind of styling
#media print {
* {
margin: 0 !important;
padding: 0 !important;
}
html,
body {
height: 100%;
overflow: visible;
}
}
I've checked your example and it's a problem related with the printer. Some printers have a "non-printable margin" by default so there is no way to print on the edges.
The user could be change manually if there are some options for scaling the document but it would be a bad solution.
My solution would be adding some margins in the CSS for the print media. For example, in this case, I 've added a left and right margin and everything it's printed correctly.
.designed__table {
width: 100%;
td,
th {
padding: 5px;
border: 1px solid;
}
}
#media print {
#page {
size: landscape;
margin: 0px 10px;
}
}
.print-container {
position: absolute;
}

Dynamically flexible width & number items with flex

I have a set of tags, that I want to show in the client. However, sometimes you might have too many tags and you want to show only one row of tags maximized to your body's width without setting a fixed number of columns or item width, and adding a show more button at the end of the tag list with the same style as a tag.
I have achieved this using Javascript in my Angular project by doing the following:
Find out the width of your tags container dynamically, with ViewChild on my content container:
let contentWidth = this.contentContainer.nativeElement.clientWidth;
Calculate the text width of the see more button and use it to calculate the new content width minus see more button width:
Calculating text function does the following:
const canvas = document.createElement('canvas'); // create a canvas
const context = canvas.getContext('2d'); // get the context
context.font = '12px avertastd-bold'; // set up your font and size
And calculate the text width:
const seeMoreButtonWidth = context.measureText(seeMoreButtonText).width;
Create a new array variable 'previewTags' which will hold the tags that are visible when the tags body is in collapsed state, and fill in as many tags as you can by calculating each tag's width with it's content text you receive from the API by checking if the next tag + its padding (static value) fits into the width.
(Not runnable here)
for (const tag of this.data.tags) {
const width = context.measureText(tag).width;
if (contentWidth - (width + this.tagsPadding) > 0) {
previewTags.push({text: tag});
contentWidth -= (width + this.tagsPadding);
} else {
break;
}
}
Push the see more button at the end of previewTags list:
previewTags.push({text: seeMoreButtonText, isButton: true});
And it looks like this in the html:
<ng-container *ngFor="let tag of previewTags">
<div class="tag" [ngClass]="{'see-more-button': tag.isButton}">{{tag.text}}</div>
</ng-container>
Output:
Resize:
As you see, now the tags are flexiable (this code does not include the show more functionality).
After giving you this background and understanding of what I am doing, I would love to ask if this is possible to achieve with css or less JavaScript intervation?
Something like this could be a pure css solution if your tags have a constant height. I just let the flex-list wrap around and then don't show the overlap.
.content_wrapper {
display: flex;
justify-content: flex-start;
flex-direction: rows;
}
.tag_wrapper {
display: flex;
justify-content: flex-start;
flex-direction: rows;
flex-wrap: wrap;
width: 80%;
height: 32px;
overflow: hidden;
}
.tag_wrapper div {
width:100px;
height:30px;
border: 1px solid black;
}
button {
flex-grow: 4;
}
<div class="content_wrapper">
<div class=tag_wrapper>
<div>Tag1</div>
<div>Tag2</div>
<div>Tag3</div>
<div>Tag4</div>
<div>Tag5</div>
<div>Tag6</div>
<div>Tag7</div>
<div>Tag8</div>
<div>Tag9</div>
</div>
<button>See more</button>
You could probably make the "See more" button solution more elegant, to not have as much white space but I'll leave that to you :)
Here is some javascript to remove the see-more button if it's not needed.
(OBS) this only works if all the tags are the exact same width and have the same margin. I did this to avoid looping through all values and checking their width individually.
(I know the list is in the wrong order, I made it like that to get the see-more button fit in well without having to tinker a bunch.
function getWidthWithMargin(elem) {
var style = elem.currentStyle || window.getComputedStyle(elem)
margin = parseFloat(style.marginLeft) + parseFloat(style.marginRight)
return(elem.getBoundingClientRect().width + margin)
}
function handleWindowSizeChange() {
let tags = document.getElementsByClassName("tag");
if(tags.length != 0)
{
let tag_width = getWidthWithMargin(tags[0]);
if(tags[0].parentElement.getBoundingClientRect().width/tag_width > tags.length) {
document.getElementById("see-more-button").style.display = "none";
}
else{
document.getElementById("see-more-button").style.display = "block";
}
}
}
window.onload = handleWindowSizeChange;
window.onresize = handleWindowSizeChange;
.content_wrapper {
}
.tag_wrapper {
display: flex;
justify-content: flex-start;
flex-direction: row-reverse;
flex-wrap: wrap;
width: 100%;
height: 32px;
overflow: hidden;
}
.tag_wrapper div {
min-width:100px;
height:30px;
border: 1px solid black;
margin: 10px;
}
.tag_wrapper button {
height:30px;
flex-grow: 50;
}
<div class="content_wrapper">
<div class=tag_wrapper>
<button id="see-more-button">See more</button>
<div class="tag">Tag1</div>
<div class="tag">Tag2</div>
<div class="tag">Tag3</div>
<div class="tag">Tag4</div>
<div class="tag">Tag5</div>
<div class="tag">Tag6</div>
<div class="tag">Tag7</div>
<div class="tag">Tag8</div>
</div>

How to create two columns without blocking horizontal rows [duplicate]

This question already has an answer here:
How to reorder divs using flex box?
(1 answer)
Closed 2 years ago.
I have got a Wordpress loop of posts. This outputs some kind of post-list. To make it easy, we can consider it a ordered-list like that:
<ol>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ol>
Each list item got a unique, different height. When a certain device width is given, I want them to display side by side, without a "row like behavior". So each column should place the next post right below it, like illustrated below (no unnecessary white space below the shorter items):
Using float, flex-box and css-grid or display: inline-block did not work for me.
Although I would love to avoid two loops with the same content inside my DOM, as its a bad behavior for screen-readers etc.
Is there a solution I do not see without a lot of javascript? The internet is full of float: left; examples searching for "two columns", "flexible columns" and I did not find anything helpful.
You can use display: flex and flex-direction: column;. By adding a height (or max-height) to the parent container, you make the elements automatically go to next column. Then you can change order attribute of some element to push them into the second row.
This solution is not very generic as it will depend on the content, but it may give an idea on how you can do it.
$('li').each(function() {
$(this).css('height',Math.floor((Math.random() * 50) + 30)+"px");
})
ol {
list-style: none;
display: flex;
flex-wrap: wrap;
flex-direction: column;
max-height: 100vh;
margin:0;
padding:0;
}
li {
box-sizing: border-box;
text-align:center;
padding: 10px;
background: red;
max-width: 50%;
margin: 5px;
}
li:nth-child(2n) {
background:green;
order:1;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ol>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ol>
Important notice (added by #Marian Rick):
This approach does only work if the left column is bigger than the right one
You need to set a fixed height, which does not allow dynamic content
Both of these problems can be solved using a javascript snippet to keep the solution dynamic.
I have another fancy answer. It uses flex-direction:coulmn and the page-break-before to force every second elemend in the second column. This way you have no restriction to the height of the full list.
Please check the jsfiddle in a separate tab to check how I used the breakpoint to toggle from normal listing to two coulmns.
Also check if it runs in all targeted browser: https://caniuse.com/#search=page-break-before
section {
display: flex;
flex-wrap: wrap;
}
article {
box-sizing: border-box;
border:1px solid grey;
width: 100%;
height: 50px;
}
#media (min-width: 500px) {
section {
flex-direction: column;
}
article {
width: 50%;
}
article:nth-child(even) {
order: 2;
}
article:nth-child(2) {
/* this breaks into the second column after the 2nd child
(which is not the first element of the second half of elements) */
page-break-before: always;
}
}
/* just for demo */
article:first-child {
height: 66px;
background-color: #e0e0fe;
}
article:nth-child(4) {
height: 80px;
background-color: #aee0e0;
}
article:nth-child(6) {
height: 130px;
background-color: yellow;
}
<section>
<article>1</article>
<article>2</article>
<article>3</article>
<article>4</article>
<article>5</article>
<article>6</article>
<article>7</article>
</section>
Based on the great idea of #TemaniAfif, I have written a small, barely tested jQuery snippet, that achieves the following:
Each item will be placed as close as possible to the top, regarding to its position inside the container
While resizing the browser, each item updates its position
Its very few and fast javascript, while CSS does most of the work
The whole concept is still based on the idea of pushing items either to the left or right side, using the order: x attribute.
There is a CODEPEN DEMO to play around with.
Notice: Browser support is equal to the browser support of flex-box.
"use strict";
// DEMO STYLE - Should be removed
// calculate random heights for each item
$("li").each(function() {
$(this).css("height", Math.floor(Math.random() * 300 + 2) + "px");
});
///////////////////////
// Calculate columns
//
// 1. loop through each item.
// 2. first get the height of item
// 3. than check which column is shorter
// 4. if left column is shorter or equal, keep item on the left side
// 5. if right column is shorter, push this item to the right side
// 6. check which side will be higher
// 7. if left column is higher, assign height of column to parent container
// 8. if right column is higher, create a margin-bottom equal of the column offset and assign it to the left column
// calculation is finished. test it.
// finally add the height of the bigger column to the div
// if its the left column, assign the height of the right
var container = $("ol");
var items = container.find("li");
var breakPoint = 768; // if equal or bigger, the calculation will be fired
var calcPositions = function calcPositions() {
// quit function if its a mobile device
if ($(window).width() < breakPoint) return;
// reset margin of left column item
container.find("li.push-left").last().css("margin-bottom", "15px");
var leftColumnHeight = 0;
var rightColumnHeight = 0;
// 1. loop through each item
items.each(function(i, e) {
// 2. get height of item
var height = $(this).outerHeight(true);
// 3. check which column is shorter
if (leftColumnHeight <= rightColumnHeight) {
// 4. if left column is shorter or equal, keep item on the left side
leftColumnHeight += height;
$(this).removeClass("push-right").addClass("push-left");
return; // skip rest and continue with next item
}
// 5. if right column is shorter, push this item to the right side
// using .push-right { order: 5 } inside css
rightColumnHeight += height;
$(this).removeClass("push-left").addClass("push-right");
});
// 6. check which side will be higher
if (leftColumnHeight >= rightColumnHeight) {
// 7. if left column is higher, assign height of column to parent container
container.height(leftColumnHeight);
return; // end of function
}
// 8. if right column is higher, create a margin-bottom equal of the column offset and assign it to the left column
// otherwhise the second object can be displayed at the bottom of the left column
// get offset of columns
var columnOffset = rightColumnHeight - leftColumnHeight;
// assign offset to last element of left sidebar
container.find("li.push-left").last().css("margin-bottom", columnOffset + "px");
// assign height to container
container.height(rightColumnHeight);
};
// calculate initially
calcPositions();
// calculate on resize
$(window).resize(function() {
calcPositions();
});
/* functional classes needed for this grid */
/* keep this breakpoint in sync with "breakPoint" inside the javascript */
#media (min-width: 768px) {
ol {
display: flex;
flex-direction: column;
flex-wrap: wrap;
}
li {
max-width: 50%;
}
li.push-right {
order: 1;
margin-right: 0;
}
}
/* demo styles that can be removed */
* {
box-sizing: border-box;
}
ol {
padding: 0;
max-width: 800px;
width: 90%;
margin: 0 auto;
}
li {
background: red;
margin-bottom: 15px;
}
#media (min-width: 768px) {
li {
max-width: 49%;
margin-right: 2%;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>Breakpoint is set to >=768px for two columns:</p>
<ol>
<li>Lorem.</li>
<li>Asperiores!</li>
<li>Illum!</li>
<li>Perspiciatis!</li>
<li>Eius.</li>
<li>Est.</li>
<li>Quisquam.</li>
<li>Eaque!</li>
<li>Vero?</li>
<li>Iste?</li>
<li>Provident?</li>
<li>Ipsum.</li>
</ol>
You can do this with inline-block if you want you avoid flex for some reason. Just use media queries when you to have all items in one column.
div {
width: 95%;
margin: auto;
}
li {
background: red;
width: 49%;
min-height: 300px;
display: inline-block;
text-align: center;
font-size: 50px;
margin-top: 10px;
}
#media screen and (max-width: 600px) {
li {
width: 98%;
}
}
.one {
background: blue;
}
.three {
background: green;
}
<div>
<ol>
<li class='one'>1</li>
<li>2</li>
<li class='three'>3</li>
<li>4</li>
<li>5</li>
</ol>
</div>

CSS display:grid overflow issue

I am creating a simple web app using angularjs for managing some kind of tickets. Tickets should be displayed in grid (.ticket-container). I am using CSS display: grid and rows and columns are dynamically set based on config file. Setting of the grid columns and rows is done using this code:
vm.getGridStyleDefinition = function () {
return {
"grid-template-rows": "repeat(" + vm.numberOfRows + ", 1fr)",
"grid-template-columns": "repeat(" + vm.numberOfColumns + ", 1fr)"
}
};
The simplified structure of the page is:
HTML
<div class="container">
<div class="flex1">
<div class="ticket-container">
<ticket></ticket>
<ticket></ticket>
<ticket></ticket>
...
</div>
</div>
<div class="menu-bar"></div>
</div>
CSS
.container {
height: 100vh;
display: flex;
flex-direction: column;
}
.flex1 {
flex: 1;
align-items: stretch;
display: flex;
}
.ticket-container {
display: grid;
width: 100vw;
grid-template-rows: repeat(5,1fr); // dynamically set
grid-template-columns: repeat(3,1fr); // dynamically set
padding: 1vh;
grid-gap: 1%;
}
.menu-bar {
background-color: blue;
}
My problem is that fractions in grid (1fr), for rows, are not calculated based on the container height, but reather on the content inside the cells. I want to force the content inside the cells to take the space that is available and not to overflow, or to force the grid to squeeze the content.
Here is codepen for this issue: link
If there is another approach to create grid that its cells will not overflow, please suggest.
Thanks in advance

Cannot print a specific div

I am using this code to print a specific div
CSS
<style type="text/css" media="print">
* {
display:none;
}
#printportion {
display:block;
}
</style>
Script
<script>
var printCalender=function () {
setTimeout(window.print, 1500);
}
</script>
When I run my page in google chrome, the print preview window is blank and shows 'print preview failed'
The issue is that regardless of where your targeted element is positioned in the DOM, your * selector will match any and all parents it has (including <html> and <body>) so the element will never be shown.
See the below example:
* {
display: none;
}
#showme {
display: block;
}
<div id="showme">This will never be shown</div>
As Nit said the problem is with your * selector. You can use one selector with #media print like this:
#media print {
body.print-element *:not(.print) {
display: none;
}
}
Here you have a working example where you can print any clicked element and/or the entire normal HTML document:
function print_this(elem) {
document.body.classList.add('print-element')
elem.classList.add('print')
window.print()
document.body.classList.remove('print-element')
elem.classList.remove('print')
}
document.querySelectorAll('div').forEach(elem =>
elem.onclick = () => print_this(elem))
div {
display: inline-flex;
width: 200px;
height: 200px;
justify-content: center;
align-items: center;
background-color: #e9a9c7;
color: #39464e;
cursor: pointer;
}
#media print {
body.print-element *:not(.print) {
display: none;
}
}
<div>Print 1</div>
<div>Print 2</div>
Note: if you cannot see colors remember to click Background Graphic (Chrome) or similar in your print options.

Categories

Resources