Create a download button for a PDF table in landscape format

Hey everyone, I've been working on creating a dynamic timetable for a group without the need for pen and paper using JavaScript, HTML, and CSS. One challenge I'm facing is figuring out how to add a button that allows users to download the table in PDF format in landscape orientation. If anyone has any ideas or solutions, please feel free to share!

If you're interested, here's the link to the code on GitHub: https://github.com/zahiraaa/timetable

const timetable = document.getElementById("timetable");

const days = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"];
const hours = ["7H", "13H", "20H"];

// Creating table headers for the days
const daysHeaderRow = document.createElement("tr");
daysHeaderCell.innerHTML = "Days";
daysHeaderRow.appendChild(daysHeaderCell);
days.forEach(day => {
  const dayHeaderCell = document.createElement("th");
  dayHeaderCell.innerHTML = day;
  dayHeaderCell.colSpan = 3;
  daysHeaderRow.appendChild(dayHeaderCell);
});
timetable.appendChild(daysHeaderRow);

// Create table headers for hours
const hoursHeaderRow = document.createElement("tr");
hoursHeaderCell.innerHTML = "Hours";
hoursHeaderRow.appendChild(hoursHeaderCell);
for (let i = 0; i < days.length; i++) {
  for (let j = 0; j < 3; j++) {
    const hourHeaderCell = document.createElement("th");
    hourHeaderCell.innerHTML = hours[j];
    hoursHeaderRow.appendChild(hourHeaderCell);
  }
}
timetable.appendChild(hoursHeaderRow);

// Creating rows for individuals
const names = ["Khalfi","Redouani", "Daki", "Hamma", "Saadane", "Boughanem", "El Ansari","Badilou","Raoui", "Chouiba", "Dahmane", "Achdad", "Bouryal", "Ettouri", "Saadouni"];
for (let name of names) {
  const row = document.createElement("tr");
  const nameCell = document.createElement("td");
  nameCell.innerHTML = name;
  row.appendChild(nameCell);
  for (let i = 0; i < days.length; i++) {
    for (let j = 0; j < 3; j++) {
      const cell = document.createElement("td");
      const select = document.createElement("select");
      select.classList.add("cell");
      const options = [" ", "CP", "ME", "CL", "CE", "R"];
      options.forEach(option => {
        const optionElement = document.createElement("option");
        optionElement.value = option;
        optionElement.innerHTML = option;
        select.appendChild(optionElement);
      });
      cell.appendChild(select);
      row.appendChild(cell);
    }
  }
  timetable.appendChild(row);
}




function exportCSV() {
    var rows = document.querySelectorAll("#timetable tr");
    var csvData = [];
    for (var i = 0; i < rows.length; i++) {
        var rowData = [];
        var cells = rows[i].querySelectorAll("td, th");
        for (var j = 0; j < cells.length; j++) {
            const select = cells[j].querySelector("select");
            if(select){
                rowData.push(select.value);
            }else{
                rowData.push(cells[j].innerText);
            }
        }
        csvData.push(rowData);
    }
    var csv = Papa.unparse(csvData);
    var csvData = new Blob([csv], {type: 'text/csv;charset=utf-8;'});
    var csvURL =  null;
    if (navigator.msSaveBlob) {
        csvURL = navigator.msSaveBlob(csvData, 'timetable.csv');
    } else {
        csvURL = window.URL.createObjectURL(csvData);
    }
    var tempLink = document.createElement('a');
    tempLink.href = csvURL;
    tempLink.setAttribute('download', 'timetable.csv');
    tempLink.click();

    // Convert the CSV data to a PDF and download it
    
var pdf = new jsPDF('l','mm','a4');
pdf.addPage();
pdf.text(csv, 10, 10);
pdf.save('timetable.pdf');
}
#timetable th {
border: 1px solid #ddd;
padding: 8px;
text-align: center;
background-color: #006699; /* bleu foncé /
}
#timetable tr:nth-child(even) {
background-color: #E6E6FA; / lavande */
}

/* General layout */
body {
  background-color: #f1f1f1;
  font-family: Arial, sans-serif;
  margin: 0;
  padding: 0;
}

/* Navigation bar style */
nav {
  background-color: #333;
  color: #fff;
  display: flex;
  justify-content: space-between;
  padding: 10px 20px;
}
nav a {
  color: #fff;
  text-decoration: none;
  margin-right: 10px;
}

/* Main section style */
main {
  padding: 20px;
}

/* Title style */
h1, h2, h3 {
  color: #333;
  text-align: center;
  margin-bottom: 20px;
}

/* Paragraph style */
p {
  line-height: 1.5;
  margin-bottom: 20px;
}

/* Image style */
img {
  max-width: 100%;
}
<table id="timetable">

 <body>
 <tr>
      <td>

        <link href="table.css" rel="stylesheet">
        <script src="table.js"></script>
        <form action="table.php" method="post">

    </td>

<tr>

<button onclick="exportCSV()">Export CSV</button>

<script src="https://cdnjs.cloudflare.com/ajax/libs/PapaParse/5.1.0/papaparse.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/1.3.8/FileSaver.min.js"></script>


<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.5.3/jspdf.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/1.3.8/FileSaver.min.js"></script>
<button onclick="exportPDF()">Export PDF</button>


<script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.77/pdfmake.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.77/pdfmake.min.vfs.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.77/vfs_fonts.js"></script>


<button id="download-pdf-button">Télécharger en PDF</button>

<script>
    var downloadButton = document.getElementById("download-pdf-button");
    downloadButton.addEventListener("click", downloadPDFWithPDFMake);
</script>




   
 </body>

Answer №1

Great suggestion

Consider updating the csv header to

Days,,Monday,,,Tuesday,,,Wednesday,,,Thursday,,,Friday,,,Saturday,,,Sunday,
since csv does not support merged fields.

When printing landscape in a browser it works fine, but for jsPDF you may need to reapply it when adding a page:

pdf.addPage();

by default it is set to a4,p so

pdf.addPage('a4','l');

should do the trick.

To create custom shapes and view full syntax options, use:

pdf.addPage([841.89, 595.28],"landscape");

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The received data object appears to be currently undefined

I am currently using MapBox to display multiple coordinates on a map, but I am encountering an issue where the longitude and latitude values in my return object are showing up as undefined. Could there be a missing configuration that is preventing the data ...

The error message is indicating that the property `match` is being attempted on an undefined object. This issue is puzzling as it does not reference any specific files or

I encountered an issue while working on my project: I kept receiving the error message "Cannot read property match of undefined." Cannot read property 'match' of undefined The error points to a specific line in polyfills.js: process.version.ma ...

Dynamic Mesh modification and Raycasting in Three.js

When I clone a mesh from another mesh and then translate and rotate it, I encounter an issue with ray-casting. The point seems to be intersecting with the original position before translation and rotation. Here is a snippet of the code: const raycaster = ...

JavaScript: Repeated Depth First Exploration for hierarchical rearrangement implemented with d3's recursion()

I'm attempting to perform a depth-first search on a complex JSON object, such as the one available through this link. My goal is to generate a modified object structure that looks like this: [ { name: "Original Object", children : [ ...

Notifying the chosen option using jQuery

I have been attempting to display an alert on the webpage based on the selected option. Unfortunately, it appears that my code is not functioning properly. This is what I have tried: $(document).ready(function(){ $("select.country").change(functio ...

Requesting data asynchronously using AJAX and displaying the filtered results on a webpage using JSON

When I send a request to my node.js server for a .json file containing person information (first name, last name), I want the data to be filtered based on user input. For example: When I request the .json file from the server, it gives me a list of people ...

How does Socket.io facilitate a basic web socket connection with a specific URL?

My current project involves a client making a WebSocket request to the following URL: ws://localhost:3000/feed/XBTMUR https://i.sstatic.net/R7H9T.png On my server side, I am utilizing NodeJs with express running. I have decided to implement Socket.io in ...

The traditional function does not have access to a reference to this

For my web development project with Angular 9, I needed to add a typeahead feature using ng bootstrap typeahead. The code provided below worked perfectly: search = (text$: Observable<string>) => text$.pipe( debounceTime(150), disti ...

What is the best way to retrieve an array of strings from JSON using PHP and display them in a table format

I'm dealing with a JSON structure that looks like this: { "id": 30, "output": { "status": "ok", "data": { "text/plain": "Array({\"a\":\"orange\",\"b\":\"fruit\"},{\"a\":&bsol ...

How can the focusout event be obtained for the .editor-text within slickgrid in an AngularJS environment?

My slickgrid has editable cells, and I've noticed that when I double click on a cell in the grid, an input box with the class .editor-text appears. However, when I click on other cells, the onBeforeEditorDestroy method is triggered before removing the ...

Implementing pagination in an express application

I am faced with a situation where I have an array of JSON objects generated by a function in my running Express app. When there is only one object, it is rendered using the following Jade view. p You searched for '#{prop}' h2 Result if res ...

Tips on retrieving a result from mongoose's findOne() function

I created a custom function using the findOne() method in Mongoose and now I need to use the result for another function. How can this be achieved? Thank you! module.exports.retrieveDeal = function(dealRequest){ Deal.findOne({name:dealRequest},functi ...

Creating a mat-tree component in Angular Material 6.0.1: Step-by-step guide

I am encountering an issue with my material angular mat-tree based application. The code runs without errors, but the values are not displayed on the screen. I need help resolving this problem so that I can proceed with the development. Upon opening the a ...

Using MongoDB in a feathers.js Hook

I'm struggling to make a feathers.js hook wait for a MongoDB call to complete before proceeding. I've tried using returns and promises, but so far nothing has worked. How can I ensure the hook waits for the database query to finish? ...

Is it possible to combine two conditions using CSS?

Hello, I have a question about CSS. In my navigation bar, I have 3 links with different styles: #p1 { font-family: Arial, Helvetica, sans-serif; font-size: 13px; line-height: 45px; font-weight: bolder; color: #999999; text-dec ...

A JavaScript function that completely empties all the input fields within a form

Seeking a jQuery function that can reset all form fields post submission. Unfortunately, I don't have any specific HTML code to provide, so looking for something generic. Any assistance would be greatly appreciated! Thank you! ...

Error Alert: Next.js TypeScript is reporting that the necessary packages are missing from your setup

As I work on developing a basic Next.js website using their TypeScript starter, everything was going smoothly with the 'yarn dev' command. However, out of nowhere, I started encountering an error message whenever I tried to run 'yarn dev&apo ...

How to update a nested object within an array in mongoose by referencing its specific id

Here is a glimpse of my database where I am looking to update an object within the perDayDetails array using its unique identifier in Mongoose. "_id":{"$oid":"612f45863106a21bc0506a36"}, "fullname":"abc xyz" ...

Utilize auto-suggestion feature for populating dynamically created input fields with information sourced from the

I have searched through numerous questions on stackoverflow related to my issue, but I was unable to apply any of them to solve my problem. Therefore, I am providing the files that I have been working with. I have successfully implemented autocomplete fe ...

What is the best way to produce a random integer within the range of 0 and 2

Here is the code snippet: var i = prompt('Please choose Rock, Paper or Scissors:'); var b = ['Rock', 'Paper', 'Scissors']; Now, I need help in generating a random number between 0-2. My initial idea was to do t ...