I am working on documents that can be many pages long with many different formatting variables. Most of the work is done in deeply nested OL tags and tables. Some of the ol tags use classes to split between grid 2 (1fr 1fr) while some stay block level. I need logic that can split the pages without overflow, while keeping a specified footer. This is using Angular. Note: The HTML is wrapped in the component, and passes ID number and rightstext (disclaimer) which is used as a ocnsistent footer across pages. Ive attempted to use paginatino logic on a single page to split it across the same page. import { Component, AfterViewInit, ElementRef, ViewChild, Input, } from '@angular/core'; @Component({ selector: 'app-dynamic-form-page', templateUrl: './dynamic-form-page.component.html', styleUrls: [ '/src/assets/styles/forms.scss', './dynamic-form-page.component.scss', ], }) export class DynamicFormPageComponent implements AfterViewInit { @Input() formId: string = ''; @Input() rightsText: string = ''; //For footers @ViewChild('fullContent', { static: false }) fullContent: ElementRef; constructor() {} pages: string[] = []; // Array to hold pages of content readonly totalPageHeight = 1056; readonly pagePadding = 192; readonly pageHeight = this.totalPageHeight - this.pagePadding; ngAfterViewInit() { this.paginateContent(); // Call the pagination logic after the view is initialized } paginateContent() { const contentElement = this.fullContent.nativeElement; // The content to paginate let currentPageContent = ''; // Store content for each page let currentHeight = 0; // Track the current page height const parentElement = document.createElement('div'); // Simulated page parentElement.style.width = '8.5in'; parentElement.style.height = '11in'; parentElement.style.position = 'absolute'; // Off-screen element parentElement.style.visibility = 'hidden'; document.body.appendChild(parentElement); // Add off-screen for height calculations let tempContainer = document.createElement('div'); tempContainer.innerHTML = contentElement.innerHTML; // Load all content into a temporary container while (tempContainer.firstChild) { const nextElement = tempContainer.firstChild; // Only handle element nodes if (nextElement.nodeType === 1) { const clonedElement = nextElement.cloneNode(true) as HTMLElement; parentElement.appendChild(clonedElement); // Add clone to simulate the page const elementHeight = clonedElement.offsetHeight; // Get height of the current element console.log( 'Current element:', clonedElement.outerHTML.slice(0, 100), 'Height:', elementHeight ); // Handle large elements: if an element is too big for the page, move it to the next page if (elementHeight > this.pageHeight) { console.log('Large element detected. Moving it to the next page.'); this.pages.push(`${currentPageContent}`); // Push the current page content currentPageContent = ''; // Start fresh for the next page parentElement.innerHTML = ''; // Clear simulated container currentHeight = 0; // Reset height currentPageContent += (nextElement as HTMLElement).outerHTML; // Start the next page with this element currentHeight = elementHeight; // Set the height for the new page tempContainer.removeChild(nextElement); // Remove the processed element continue; } // If adding this element exceeds the page height, create a new page if (currentHeight + elementHeight > this.pageHeight) { this.pages.push(`${currentPageContent}`); // Save the content for this page console.log( `Page ${this.pages.length + 1} created. Content length: ${ currentPageContent.length }` ); currentPageContent = ''; // Start fresh for the next page parentElement.innerHTML = ''; // Clear the simulated page container currentHeight = 0; // Reset height for the new page } // Accumulate the outerHTML of the current element into the page content currentPageContent += (nextElement as HTMLElement).outerHTML; currentHeight += elementHeight; // Update the current height } // Remove the processed element from tempContainer tempContainer.removeChild(nextElement); // Clean up the original content } // Ensure the final page is added, even if it's not a full page if (currentPageContent.trim().length > 0) { this.pages.push(`${currentPageContent}`); // Push the last page console.log(`Final page created. Total pages: ${this.pages.length}`); } // Remove the simulated element from the DOM document.body.removeChild(parentElement); // Add footers to all pages const totalPages = this.pages.length; this.pages = this.pages.map((pageContent, index) => this.addFooter(pageContent, index, totalPages) ); } addFooter(content: string, pageIndex: number, totalPages: number): string { return ` <div class="page-content"> ${content} <div class="dynamic-footer"> <table> <tr> <td class="td2 left bold">${this.formId}</td> <td class="disclaimer td3">${this.rightsText}</td> <td class="td2 right bold">Page ${ pageIndex + 1 } of ${totalPages}</td> </tr> </table> </div> </div> `; } } The issue with this, even though the styling for the double list remains intact, is that the ol elements nested will overflow outside of the page. I've attempted splitting the ol>li elements nested into their own elements, but that removed the needed styling and created some overflow on the pages still. Continue reading...