11

I am trying to add page numbers to my html print out and came across Counter Increment. I tried using it for my pages, but it is only showing Page 1 every time. Help would be appreciated.

P.S. I have already tried following other solutions similar to mine, but none work so far. My case is different because I am using it inside of a table header.

.page-number{
    text-align:center;
}
thead {
    display:table-header-group;
}

@media print{
     .page-number:before{
        counter-increment: page;
        content: "Page " counter(page);
     }
   }
@media screen{
    .page-number:before {
        counter-increment: page;
        content: "Page " counter(page);
        }
     }
<table class="SetupMainTable">
  <thead>
    <tr>
       <td colspan="4">Company Name</td>
       <td colspan="5" class="right" style="font-size:25px;">Daily Time Ticket</td> 
       <td colspan="1"><div class="page-number"></div></td>
    </tr>
  </thead>
</table>  

Eg:Example that print's same Page 1 on all pages

Expected Answer

It Should print incremental Page 1 Page 2 Page 3 number on all pages after pressing ctrl + p Print


Long story short:

Press Ctrl + P → Print current window → Add a footer in the bottom of the page(Current Window) like Page <counter> counter is a number starting from 1 .

So the Page will be like

enter image description here

PS: Counter shouldn't visible on the page

Stephen Romero
  • 2,812
  • 4
  • 25
  • 48
  • In FF it actually prints only on the last page the right number (3) . nothing nor 1 or 2 are printed on the first 2 pages. – G-Cyrillus May 30 '20 at 16:03

6 Answers6

3

So I was never able to get this to work for my case. I know other cases may work with above answers, but I could not get the Front-End alone to generate the dynamic page numbers.

I used help from my back-end, which is PHP in my case and used a plugin called wkhtmltopdf.

This solved my issue, https://stackoverflow.com/a/13496899/6000966.

I was able to remove the logic from the front-end and place it on the back-end and let it handle the dynamic page numbers.

I would advise if the HTML pages are using dynamic data from the back-end, something like this is the way to go.

Static pages on the other hand should work with the above answers.

Stephen Romero
  • 2,812
  • 4
  • 25
  • 48
  • 1
    After hours of try, I gave up by doing it with pure css. Then I found your question and it's answer. Thanks – Rafe May 09 '22 at 09:03
2

I found that code in one Russian article. That code adds pagination to each page:

@page:right{
  @bottom-right {
    content: counter(page);
  }
}

@page:left{
  @bottom-left {
    content: counter(page);
  }
}

And code below can show number of page of their total like "Page 3 of 120".

@page:left{
  @bottom-left {
    content: "Page " counter(page) " of " counter(pages);
  }
}
Alyona Yavorska
  • 569
  • 2
  • 14
  • 20
  • actually, you can check that, just use google translate page, [link](http://bot.kz/2015/01/34667) – Alyona Yavorska May 31 '20 at 07:44
  • can you please create working example by forking any example on this page, You can use [https://plnkr.co/](https://plnkr.co/) For quick reference you can use other code examples on this page – vijay May 31 '20 at 08:43
1

Apply counter-reset: page; to the parent element that holds all of the page number elements. Also note, that based on your snippet, it appears you want .page-number (class), not #page-number (id). id attributes are unique throughout the document, while class attributes can be repeated the same identifier.

table {
  text-align: center;
  counter-reset: page;
}

.large-font {
  font-size: 25px;
}

@media screen {
  .page-number:before {
    counter-increment: page;
    content: "Page " counter(page);
  }
}
<table>
  <tr>
    <td colspan="4">Company Name</td>
    <td colspan="5" class="right large-font">Daily Time Ticket</td>
    <td colspan="1">
      <div class="page-number"></div>
    </td>
  </tr>
  <tr>
    <td colspan="4">Company Name</td>
    <td colspan="5" class="right large-font">Daily Time Ticket</td>
    <td colspan="1">
      <div class="page-number"></div>
    </td>
  </tr>
  <tr>
    <td colspan="4">Company Name</td>
    <td colspan="5" class="right large-font">Daily Time Ticket</td>
    <td colspan="1">
      <div class="page-number"></div>
    </td>
  </tr>
</table>
Miroslav Glamuzina
  • 4,472
  • 2
  • 19
  • 33
  • Thank you for your suggestion, I realize now the ID was a mistake on my part, will update question. However I see you're adding the rows statically to the table. That works on the same page, but unfortunately I am needing it to count per page. It also duplicated the headers which is not what I am needing. I updated the question to give a bit more details – Stephen Romero Jun 01 '19 at 20:17
1

Not sure about your intended output but if you try this snippet I think it does what you are asking [i.e. incrementing the page number]. The code was readapted from [this original sample] 1

body {
  /* Set "my-sec-counter" to 0 */
  counter-reset: my-sec-counter;
}

h2::before {
  /* Increment "my-sec-counter" by 1 */
  counter-increment: my-sec-counter;
  content: "Section " counter(my-sec-counter) ". ";
}

#page-number::before {
  /* Increment "my-sec-counter" by 1 */
  counter-increment: my-sec-counter;
  content: "Page " counter(my-sec-counter) ". ";
}
<h2>HTML Tutorial</h2>
<h2>CSS Tutorial</h2>
<h2>JavaScript Tutorial</h2>
<h2>Bootstrap Tutorial</h2>
<h2>SQL Tutorial</h2>
<h2>PHP Tutorial</h2>

<tr>
  <td colspan="4">Company Name</td>
  <td colspan="5" class="right" style="font-size:25px;">Daily Time Ticket</td>
  <td colspan="1">
    <div id="page-number"></div>
  </td>
</tr>

<tr>
  <td colspan="4">Company Name</td>
  <td colspan="5" class="right" style="font-size:25px;">Daily Time Ticket</td>
  <td colspan="1">
    <div id="page-number"></div>
  </td>
</tr>
Dharman
  • 30,962
  • 25
  • 85
  • 135
Antonino
  • 3,178
  • 3
  • 24
  • 39
0

First of all, it was quite a challenge answering this question. Secondly, why weren't the other examples just working? That's because the counter only fires on every element. When you print, the browser doesn't create new instances of <thead>, at least to source code of your website. It just simply displays it. However, this behaviour can be bypassed by, before printing ('beforeprint'), altering the DOM and recreating the print pages with Javascript. Now, on every page there's a new <table> with a new instance of <thead>. Now, the counter works. After printing this code automatically resets the DOM to the state before printing. The User Experience stays the same.

With const pixelHeightA4 = 1000; you can specify how many pixels fit one a4. 1000 comes really close when I was testing.

With const heightOfTHead = 160; you specify the height of the table header on an a4 size.

I hope the comments in code can explain the process.

//alter the dom to print the elements
window.addEventListener('beforeprint', event => {
  //specify the number of rows in the tBody per page

  //You can either hardcode this number or change it for every page with code
  var table = document.getElementsByClassName('SetupMainTable')[0];

  printTableData(table);
  table.style.display = 'none';
});

function printTableData(table) {
  //initialise the table to get the data from
  var table = table.querySelectorAll('tbody')[0];
  var tBody;
  //get the template table
  let temp = document.getElementsByTagName('template')[0];
  //get the number of element for the last page
  const pixelHeightA4 = 1000;
  const heightOfTHead = 160;
  var heightOfContent = heightOfTHead;

  for (var i = 0, row; row = table.rows[i]; i++) {
    //get the height of the current row
    var rowHeight = row.getBoundingClientRect().height;
    var nextRowHeight;
    //get the height of the next row.
    if (i + 1 == table.rows.length) {
      nextRowHeight = 0;
    } else {
      nextRowHeight = (table.rows[i + 1]).getBoundingClientRect().height;
    }

    if (heightOfContent == 160 && table.rows.length - 1 != i) {
      //if it is the first element and not the only element on the last page
      //create new tBody
      tBody = document.createElement('tbody');
      var firstEl = row.cloneNode(true);
      heightOfContent += rowHeight;
      tBody.appendChild(firstEl);
    } else if (((heightOfContent + rowHeight) < pixelHeightA4 && (heightOfContent + rowHeight + nextRowHeight) >= 1000) || table.rows.length - 1 == i) {
      //if the row still fits on the page but the next row doesn't then this is the last table row of the page.

      if (tBody == null) {
        //if there's only one element on the last page, create a new tBody
        tBody = document.createElement('tbody');
      }

      //clone the template
      var clon = temp.content.cloneNode(true);
      //clone the row to append to the tbody
      var cloneRow = row.cloneNode(true);
      //get the table element in the template
      var cloneTable = clon.querySelectorAll('table')[0];
      //append it all togehter
      tBody.appendChild(cloneRow);
      cloneTable.appendChild(tBody);
      //append the table to the page
      document.body.appendChild(clon);

      //reset the tBody
      tBody = null;
      heightOfContent = heightOfTHead;
    } else {
      //clone a row and append it to the tBody
      var cloneRow = row.cloneNode(true);
      heightOfContent += rowHeight;
      tBody.appendChild(cloneRow);
    }

    console.log(heightOfContent);
  }
}

//reset the dom to the state before print
window.addEventListener('afterprint', event => {
  var table = document.getElementsByClassName('SetupMainTable');
  table[0].style.display = 'table';
  //remove all the cloned tables
  var cloneTables = document.getElementsByClassName('templateTable');
  while (cloneTables.length > 0) {
    cloneTables[0].parentNode.removeChild(cloneTables[0]);
  }
});
@media print {
  body {
    counter-reset: page;
    color: red;
  }
  .page-number:before {
    counter-increment: page;
    content: "Page "counter(page);
  }
  table {
    break-after: page !important;
    border: 1px solid grey;
    border-collapse: collapse;
  }
  .templateTable {
    display: table;
  }
}

@media screen {
  body {
    counter-reset: page;
  }
  .page-number {
    text-align: center;
  }
  table {
    border: 1px solid grey;
    border-collapse: collapse;
  }
  thead {
    display: table-header-group;
  }
  .page-number:before {
    counter-increment: page;
    content: "Page "counter(page);
  }
  .templateTable {
    display: none;
  }
}

table td,
table th {
  border: 1px solid black;
}

table tr:first-child th {
  border-top: 0;
}

table tr:last-child td {
  border-bottom: 0;
}

table tr td:first-child,
table tr th:first-child {
  border-left: 0;
}

table tr td:last-child,
table tr th:last-child {
  border-right: 0;
}
<!-- Extra big table with different row seizes for demonstration purposes only -->

<body>
  <table class="SetupMainTable">
    <thead>
      <tr>
        <th colspan="4">Company Name</th>
        <th colspan="5" class="right" style="font-size:25px;">Daily Time Ticket</th>
        <th colspan="1">
          <div class="page-number"></div>
        </th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td colspan="5">123</td>
        <td colspan="5">abc</td>
      </tr>
      <tr>
        <td colspan="5">456</td>
        <td colspan="5">def</td>
      </tr>
      <tr>
        <td colspan="5">
          <h3>header for random dynamic height</h3>
        </td>
        <td colspan="5">ghi</td>
      </tr>
      <tr>
        <td colspan="5">101112</td>
        <td colspan="5"><img src="https://cdn.sstatic.net/stackexchange/img/logos/so/so-logo.png" height="100"></td>
      </tr>
      <tr>
        <td colspan="5">131416</td>
        <td colspan="5">mno</td>
      </tr>
      <tr>
        <td colspan="5">171819</td>
        <td colspan="5">pqr</td>
      </tr>
      <tr>
        <td colspan="5"><small>small text</small></td>
        <td colspan="5">
          <h1>Big text</h1>
        </td>
      </tr>
      <tr>
        <td colspan="5">132435</td>
        <td colspan="5">vwx</td>
      </tr>
      <tr>
        <td colspan="5">1325125123</td>
        <td colspan="5">yza</td>
      </tr>
      <tr>
        <td colspan="5">xy2532351235z</td>
        <td colspan="5">bcd</td>
      </tr>
      <tr>
        <td colspan="5">12351235125</td>
        <td colspan="5">efg</td>
      </tr>
      <tr>
        <td colspan="5">1253251235</td>
        <td colspan="5">hij</td>
      </tr>
      <tr>
        <td colspan="5">2315346</td>
        <td colspan="5">klm</td>
      </tr>
      <tr>
        <td colspan="5">123</td>
        <td colspan="5">abc</td>
      </tr>
      <tr>
        <td colspan="5">456</td>
        <td colspan="5">def</td>
      </tr>
      <tr>
        <td colspan="5">
          <h3>header for random dynamic height</h3>
        </td>
        <td colspan="5">ghi</td>
      </tr>
      <tr>
        <td colspan="5">101112</td>
        <td colspan="5"><img src="https://cdn.sstatic.net/stackexchange/img/logos/so/so-logo.png" height="100"></td>
      </tr>
      <tr>
        <td colspan="5">131416</td>
        <td colspan="5">mno</td>
      </tr>
      <tr>
        <td colspan="5">171819</td>
        <td colspan="5">pqr</td>
      </tr>
      <tr>
        <td colspan="5"><small>small text</small></td>
        <td colspan="5">
          <h1>Big text</h1>
        </td>
      </tr>
      <tr>
        <td colspan="5">132435</td>
        <td colspan="5">vwx</td>
      </tr>
      <tr>
        <td colspan="5">1325125123</td>
        <td colspan="5">yza</td>
      </tr>
      <tr>
        <td colspan="5">xy2532351235z</td>
        <td colspan="5">bcd</td>
      </tr>
      <tr>
        <td colspan="5">12351235125</td>
        <td colspan="5">efg</td>
      </tr>
      <tr>
        <td colspan="5">1253251235</td>
        <td colspan="5">hij</td>
      </tr>
      <tr>
        <td colspan="5">2315346</td>
        <td colspan="5">klm</td>
      </tr>
      <tr>
        <td colspan="5">123</td>
        <td colspan="5">abc</td>
      </tr>
      <tr>
        <td colspan="5">456</td>
        <td colspan="5">def</td>
      </tr>
      <tr>
        <td colspan="5">
          <h3>header for random dynamic height</h3>
        </td>
        <td colspan="5">ghi</td>
      </tr>
      <tr>
        <td colspan="5">101112</td>
        <td colspan="5"><img src="https://cdn.sstatic.net/stackexchange/img/logos/so/so-logo.png" height="100"></td>
      </tr>
      <tr>
        <td colspan="5">131416</td>
        <td colspan="5">mno</td>
      </tr>
      <tr>
        <td colspan="5">171819</td>
        <td colspan="5">pqr</td>
      </tr>
      <tr>
        <td colspan="5"><small>small text</small></td>
        <td colspan="5">
          <h1>Big text</h1>
        </td>
      </tr>
      <tr>
        <td colspan="5">132435</td>
        <td colspan="5">vwx</td>
      </tr>
      <tr>
        <td colspan="5">1325125123</td>
        <td colspan="5">yza</td>
      </tr>
      <tr>
        <td colspan="5">xy2532351235z</td>
        <td colspan="5">bcd</td>
      </tr>
      <tr>
        <td colspan="5">12351235125</td>
        <td colspan="5">efg</td>
      </tr>
      <tr>
        <td colspan="5">1253251235</td>
        <td colspan="5">hij</td>
      </tr>
      <tr>
        <td colspan="5">2315346</td>
        <td colspan="5">klm</td>
      </tr>
      <tr>
        <td colspan="5">123</td>
        <td colspan="5">abc</td>
      </tr>
      <tr>
        <td colspan="5">456</td>
        <td colspan="5">def</td>
      </tr>
      <tr>
        <td colspan="5">
          <h3>header for random dynamic height</h3>
        </td>
        <td colspan="5">ghi</td>
      </tr>
      <tr>
        <td colspan="5">101112</td>
        <td colspan="5"><img src="https://cdn.sstatic.net/stackexchange/img/logos/so/so-logo.png" height="100"></td>
      </tr>
      <tr>
        <td colspan="5">131416</td>
        <td colspan="5">mno</td>
      </tr>
      <tr>
        <td colspan="5">171819</td>
        <td colspan="5">pqr</td>
      </tr>
      <tr>
        <td colspan="5"><small>small text</small></td>
        <td colspan="5">
          <h1>Big text</h1>
        </td>
      </tr>
      <tr>
        <td colspan="5">132435</td>
        <td colspan="5">vwx</td>
      </tr>
      <tr>
        <td colspan="5">1325125123</td>
        <td colspan="5">yza</td>
      </tr>
      <tr>
        <td colspan="5">xy2532351235z</td>
        <td colspan="5">bcd</td>
      </tr>
      <tr>
        <td colspan="5">12351235125</td>
        <td colspan="5">efg</td>
      </tr>
      <tr>
        <td colspan="5">1253251235</td>
        <td colspan="5">hij</td>
      </tr>
      <tr>
        <td colspan="5">2315346</td>
        <td colspan="5">klm</td>
      </tr>

    </tbody>
  </table>
  <template id="tables">
      <table class="SetupMainTable templateTable">
        <thead>
          <tr>
            <th colspan="4">Company Name</th>
            <th colspan="5" class="right" style="font-size:25px;">Daily Time Ticket</th>
            <th colspan="1">
              <div class="page-number"></div>
            </th>
          </tr>
        </thead>
      </table>
    </template>
</body>

Hope this helps, if not, please comment!

Edit1:

It automatically calculates the amount of rows that can fit on one a4 based on the row height of each individual <tr>.

You can test it here (Tested it on chrome)

Community
  • 1
  • 1
Chiel
  • 1,324
  • 1
  • 11
  • 30
  • you hardcoded number of rows/page and row height, which is not a great solution, both could be random for a `Generic` solution – vijay May 31 '20 at 06:58
  • @vijay I've made [this plunk](https://embed.plnkr.co/plunk/koYV0fXfEmddTOs1) as a sample. – Chiel May 31 '20 at 08:16
  • still a generic solution is needed , regardless of row height and rows on page , it should not break.Which in you case its breaking – vijay May 31 '20 at 08:42
  • @vijay what do you mean it breaks. The other i could maybe look into it later today. – Chiel May 31 '20 at 08:46
  • break means, Eg row height 100px - so if by any means row size increases, and overflows out of 100px 2 things can happen, 1st overflown text is Cut , 2nd overflown text is printed on next page pushing down all the rows and futher create `BIG EMPTY GAPS` – vijay May 31 '20 at 08:51
  • and lets say if i use `page-break-inside: avoid;` css on `` it will print the single `` on new page creating gaps allover – vijay May 31 '20 at 08:54
  • @vijay The edit provides a dynamic amount of `` elements per page. – Chiel May 31 '20 at 21:59
-1

[Updated Answer]

Try this. It's working fine as you wanted it to work

var counter = 1;
 
function printPageCounter(){
        document.title="Page "+counter+"";
        
        $("#pageNumber").append("Page Number : "+counter+"");
        window.print();
        $("#pageNumber").empty();
        counter++;
        return true;
 }

jQuery(document).bind("keyup keydown", function(e){
    if(e.ctrlKey && e.keyCode == 80){
     printPageCounter();
    }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<html>
    <head>
    <title>My title</title>
    </head>
    <body>
    <div id="pageNumber"></div>
    <H1>Just press ctrl + p  Or Just press this button <H1>


<button onClick="printPageCounter();">Try it</button>

    </body>
    </html>

enter image description here

Dupinder Singh
  • 7,175
  • 6
  • 37
  • 61
  • it dosen't works - https://plnkr.co/plunk/nQSgHfyelcUGlIFj please fork/update/create new example before publishing answer – vijay May 31 '20 at 07:16
  • @vijay doesn't work? What are your test cases. do you just want, on every press of `ctrl` + `p` the page print and page name should be `page` like `Page 1`, `page 2` , `page 3` ..... and so on until page refresh. with page refresh counter reset? is this what you want ? or do you have other specifications? – Dupinder Singh Jun 02 '20 at 14:22
  • It dosent matter you refresh or not , all matters is incremented pagenumbers on all pages after print command – vijay Jun 03 '20 at 07:10
  • So what you think, what is the problem in my solution? when I press ctrl + P it print page+Counter . – Dupinder Singh Jun 03 '20 at 07:36
  • please check plnkr link in start of this comment – vijay Jun 03 '20 at 09:45
  • @vijay if nobody is able to give you the answer then I think you need to rephrase your question. Try to explain your problem a bit more clearly – Dupinder Singh Jun 03 '20 at 09:52
  • 1
    hmm you are right i need to rephrase it , and also in question there are very less rows, also your eg had less rows **BUT** problem occours when there are lots of rows, let me again rephrase it .Thanks – vijay Jun 03 '20 at 10:02
  • BTW just one question. do you want what I added in screenshot? – Dupinder Singh Jun 03 '20 at 10:31
  • no , it should print on pages header, or bottom of every page only – vijay Jun 03 '20 at 10:34
  • @vijay, I updated the answer, It is appending page numer at the top left corner as shown in screenshot. Have a look :) – Dupinder Singh Jun 03 '20 at 12:08
  • What do you mean by aother pages! Is there page chnage after pressing Ctrl + P . BTW now you have the logic try to implement on your code! Might help, or you can give your code I will try to fix it – Dupinder Singh Jun 04 '20 at 02:59
  • [Code Editor link](https://embed.plnkr.co/plunk/mHcC5gRwwMnSHrxM) – vijay Jun 04 '20 at 06:22
  • "What do you mean by aother pages!" means once you give print command, and lets say you have total 3 pages then sequentially on all pages it should show `page1`, `page2`, `page3` – vijay Jun 04 '20 at 06:28
  • in your case if you add `200 rows` , it shows `Page Number : 1` only on 1st page , and on second page it dosent shows – vijay Jun 04 '20 at 06:30
  • finally its woking hun? – Dupinder Singh Jun 09 '20 at 04:46