So teilen Sie HTML-Seiten in A4-Größe in Angular 9

Sep 30 2020

Ich versuche so etwas wie in Xing the CV Maker zu erstellen -> https://lebenslauf.com/.

Ich habe verschiedene Arrays von Objekten. Ich kann jedoch keine A4-Seiten erstellen, die die Daten rendern. Wenn das Array größer als eine Seite ist, erstellen Sie eine neue Seite A4 und fügen Sie dort Daten hinzu. Die Funktion muss so sein, wenn das Array für eine Größe größer ist, dann erstellen Sie eine neue Seite a4 und legen Sie die Daten dort ab. Im Stackblitz habe ich ein Array und zufälligen Text hinzugefügt und einen A4-Buchstaben entworfen. Ich bezog mich auf diese Frage und Antwort, half mir aber nicht zu viel. CSS zum Einstellen des A4-Papierformats .
Ich habe versucht, die Paginierung vorzutäuschen und A4-Größen zu erstellen, aber es hat nicht funktioniert.
Ich habe in diesem Code mit jquery dort gesucht. Es funktioniert, aber ich kann es nicht in Angular kompilieren.https://jsfiddle.net/tm637ysp/10/ Kann mir hier jemand helfen?

Ich habe zwei Projekte in stackblitz erstellt. Vielleicht helfen sie.
https://stackblitz.com/edit/angular-ivy-fjhpdu.
https://stackblitz.com/edit/angular-ivy-uzmdwg

Ich wollte diese Frage erneut öffnen, da die genehmigte Antwort von @HirenParekh nicht wie gewünscht funktioniert. Das Problem ist jetzt, wenn der Text in einem Objekt sehr groß ist, wird keine neue Seite in Echtzeit hinzugefügt, sondern nur, wenn ich die Seite neu lade. Ich denke, dass der Code zum Hinzufügen einer neuen Seite oder zum Bearbeiten der Seite nur in gerendert wird ngOnInit. Die Richtlinie, die für diese Aufgabe vorgesehen ist, funktioniert meines Erachtens nicht wie ausgenommen. Hier ist das, stackblitzwas er versucht hat, mir zu helfen.https://stackblitz.com/edit/angular-ivy-zjf8rv

Dies ist der Code, den ich versuche, Daten anzuzeigen.

    <div style="transition: transform 0.25s ease 0s;transform: scale(1.3);transform-origin: 50% 0px 0px;backface-visibility: hidden;perspective: 1000px;display: block;margin: 0px 11.5385%;font-size:10px;width: 76.9231%;-webkit-font-smoothing: antialiased;">
<app-paginated-view [pageSize]="'A4'" *ngIf="model" class="Grid-grid-column">
  <div pageContent class="row">
    <div class="col col-lg-7">
      <h4>{{currentUser?.firstName}} {{currentUser?.lastName}}</h4>
    </div>
    <div class="col text-right">
      <input type="file" accept="image/*" (change)="readUrl($event)"> <img [src]="url" (change)="readUrl($event)" height="128" style="cursor:  pointer">

    </div>
  </div>

  <div pageContent class="Unit-unit-unitGroup"
   *ngFor="let personalData of model.personalData; let id = index">
   <div pageContent [ngClass]="{ 'isCatActive': selectedCategory === category.PersonalData}">

   <ng-container *ngIf="selectedCategory === category.PersonalData" clickOutside (clickOutside)="removeClick()">
    <ul>
      <li class="fa fa-plus addIconTop" (click)="openDialog()"></li>
      <li class="fa fa-plus addIconBottom" (click)="openDialog()"></li>
      <li class="fa fa-trash deleteIconRight" (click)="deleteCategory(index)"></li>
      <li class="fa fa-arrow-down moveIconDown"></li>
      <li class="fa fa-arrow-up moveIconTop"></li>
    </ul>
  </ng-container>

    <div pageContent class="col-md-12" (click)="setCategory(category.PersonalData)">
      <div class="row height">
      <div  class="col-md-4 col-sm-6 text-right tLine"></div>
      <h3 class="first-template-paragraphTitle Paragraph-paragraph-title height">
        <div class="Text-text-wrapper">
          <div class="Text-Text-text">{{'category.PersonalData' | translate}}</div>
        </div>
      </h3>
    </div>
    </div>
    <div pageContent class="container-fluid">
      <ng-container>
      <app-personal-data [personalData]="personalData" [model]="model" [id]="id">
    </app-personal-data>
  </ng-container>
  </div>
  </div>
  </div>

    <!-- Career Component -->
    <ng-container *ngFor="let careers of model.careers" class="Unit-unit-unitGroup">
      <div pageContent class="col-md-12">
        <div class="row height">
        <div  class="col-md-4 col-sm-6 text-right tLine"></div>
        <h3 class="first-template-paragraphTitle Paragraph-paragraph-title height">
          <div class="Text-text-wrapper">
            <div class="Text-Text-text">{{'category.Career' | translate}}</div>
          </div>
        </h3>
      </div>
      </div>
      <div class="container-fluid" pageContent>
      <ng-container *ngFor="let careerObj of careers.subCategories; let i = index">
      <app-career [careerObj]="careerObj" [id]="i" [career]="careers" [model]="model"></app-career>
      </ng-container>
      <ng-container *ngFor="let emptyObj of careers.emptySubContents; let iEmpty = index">
        <app-empty-object [emptyObj]="emptyObj" [iEmpty]="iEmpty" [model]="model" [isFromCareer]="true"></app-empty-object>
      </ng-container>
        </div>
    </ng-container>

    <!--Education Component-->
    <ng-container *ngFor="let education of model.education" class="Unit-unit-unitGroup">
      <div pageContent [ngClass]="{ 'isCatActive': selectedCategory === category.Education}">
        <ng-container *ngIf="selectedCategory === category.Education" clickOutside (clickOutside)="removeClick()">
          <ul>
            <li class="fa fa-plus addIconTop" (click)="openDialog()"></li>
            <li class="fa fa-plus addIconBottom" (click)="openDialog()"></li>
            <li class="fa fa-trash deleteIconRight" (click)="deleteCategory(index)"></li>
            <li class="fa fa-arrow-down moveIconDown"></li>
            <li class="fa fa-arrow-up moveIconTop"></li>
          </ul>
        </ng-container>
      <div pageContent class="col-md-12" (click)="setCategory(category.Education)">
        <div class="row height">
          <div class="col-md-4 col-sm-6 text-right tLine"></div>
          <h3 class="first-template-paragraphTitle Paragraph-paragraph-title height">
            <div class="Text-text-wrapper">
              <div class="Text-Text-text">{{'category.Education' | translate}}</div>
            </div>
          </h3>
      </div>
      </div>
      <div pageContent class="container-fluid">
      <ng-container *ngFor="let educationObj of education.subCategories; let i = index" class="col-md-12">
        <app-education [educationObj]="educationObj" [id]="i" [education]="education" [model]="model"></app-education>
      </ng-container>
      </div>
      </div>
    </ng-container>


  <!-- Skills Component-->
    <ng-container *ngFor="let skills of model.skills" class="Unit-unit-unitGroup">
    <div pageContent [ngClass]="{ 'isCatActive': selectedCategory === category.Skills}">
    <ng-container clickOutside *ngIf="selectedCategory === category.Skills" (clickOutside)="removeClick()">
      <ul>
        <li class="fa fa-plus addIconTop" (click)="openDialog()"></li>
        <li class="fa fa-plus addIconBottom" (click)="openDialog()"></li>
        <li class="fa fa-trash deleteIconRight" (click)="deleteCategory(index)"></li>
        <li class="fa fa-arrow-down moveIconDown"></li>
        <li class="fa fa-arrow-up moveIconTop"></li>
      </ul>
    </ng-container>
    <div pageContent class="col-md-12" (click)="setCategory(category.Skills)">
      <div class="row height">
        <div class="col-md-4 col-sm-6 text-right tLine"></div>
        <h3 class="first-template-paragraphTitle Paragraph-paragraph-title height">
          <div class="Text-text-wrapper">
            <div class="Text-Text-text">{{'category.Skills' | translate}}</div>
          </div>
        </h3>
    </div>
    </div>
          <div pageContent class="container-fluid">
      <ng-container *ngFor="let skillObj of skills.subCategories; let i = index" class="col-md-12">
        <app-skills [skillObj]="skillObj" [id]="i" [skills]="skills" [model]="model"></app-skills>
      </ng-container>
      </div>
    </div>
  </ng-container>


</app-paginated-view>
</div>

Dies ist das CSS

  .A4 {
  width: 595px;
  height: 842px;
  padding: 25px 25px;
  position: relative;
}

 

Dies ist das json

{
    "personalData": [
        {
  
            "firstName": "Max",
            "lastName": "Muster",
            "email": "[email protected]",
            "birthday": "2020-09-25T00:00:00.000Z",
            "telephone": "0123456789",
            "job": "Freelancer",
            "country": "Germany",
            "postalCode": 12345,
            "city": "None",
            "title": 2,
            "gender": 0,
            "street": "Musterman 12",
            "state": "",
            "status": 1,
            "showBirthday": true
        }
    ],
    "skills": [
        {
            "subCategories": [
                {
                    "languages": [
                        {
                            "name": "languages.de",
                            "rate": 5
                        },
                        {
                            "name": "languages.al",
                            "rate": 1
                        },
                        {
                            "name": "languages.en",
                            "rate": 5
                        },
                        {
                            "name": "languages.fr",
                            "rate": 4
                        },
                        {
                            "name": "languages.it",
                            "rate": 4
                        }
                    ],
                    "pcKnowledge": [
                        {
                            "_id": "5f5ca07e4dba443f786ea7ae",
                            "name": "Word"
                        },
                        {
                            "_id": "5f5ca07e4dba443f786ea7af",
                            "name": "Adobe Photoshop"
                        },
                        {
                            "_id": "5f5fd46bb21df2444c39f317",
                            "name": "Test"
                        },
                        {
                            "_id": "5f5fd46bb21df2444c39f318",
                            "name": "Excel"
                        },
                        {
                            "_id": "5f5fd46bb21df2444c39f319",
                            "name": "Ja"
                        },
                        {
                            "_id": "5f72339552009b4244391972",
                            "name": "Powerpoint"
                        }
                    ],
                    "skillsOffer": [
                        {
                            "_id": "5f4a4e2d718d33092df2c327",
                            "name": "Angular"
                        },
                        {
                            "_id": "5f4a4e2d718d33092df2c327",
                            "name": "Java"
                        },
                        {
                            "_id": "5f4a4e2d718d33092df2c327",
                            "name": "Typescript"
                        },
                        {
                            "_id": "5f4a4e2d718d33092df2c327",
                            "name": "html"
                        },
                        {
                            "name": "Javascript"
                        }
                    ],
                    "driveLicenses": [
                        {
                            "_id": "5f5ca07e4dba443f786ea7ac",
                            "name": "B"
                        },
                        {
                            "_id": "5f5ca07e4dba443f786ea7ad",
                            "name": "C"
                        },
                        {
                            "_id": "5f5f204faa5d0205180bd581",
                            "name": "B"
                        }
                    ],
                    "name": "",
                    "qualifications": ""
                }
            ]
        }
    ]
}

Und das ist das Paginated view class for adding new page and splitting pages

<!-- display: none style will any child that does not have #pageContent local variable defined -->
<div class="content-wrapper" #contentWrapper style="display: block">
</div>
<div class="paginated-view" #paginatedView>

</div>

export class PaginatedViewComponent implements AfterViewInit {
  @Input() pageSize: "A3" | "A4" = "A4";

  @ViewChild("paginatedView") paginatedView: ElementRef<HTMLDivElement>;

  @ViewChild("contentWrapper") contentWrapper: ElementRef<HTMLDivElement>;

  @ContentChildren(PageContentDirective, { read: ElementRef })
  elements: QueryList<ElementRef>;

  constructor(private changeDetector: ChangeDetectorRef ) {}

  ngAfterViewInit(): void {
    this.updatePages();

    // when ever childs updated call the updatePagesfunction
    this.elements.changes.subscribe((el) => {
      this.updatePages();
    });
  }


  updatePages(): void {
    // clear paginated view
    this.paginatedView.nativeElement.innerHTML = "";

    // get a new page and add it to the paginated view
    let page = this.getNewPage();
    this.paginatedView.nativeElement.appendChild(page);

    let lastEl: HTMLElement;
    // add content childrens to the page one by one
    this.elements.forEach((elRef) => {
      const el = elRef.nativeElement;

      // if the content child height is larger than the size of the page
      // then do not add it to the page

      if (el.clientHeight > page.clientHeight) {
        return;
      }
      // add the child to the page
      page.appendChild(el);

      // after adding the child if the page scroll hight becomes larger than the page height
      // then get a new page and append the child to the  new page
      if (page.scrollHeight > page.clientHeight) {
        page = this.getNewPage();
        this.paginatedView.nativeElement.appendChild(page);
        page.appendChild(el);
      }
      lastEl = el;
    });
    this.changeDetector.detectChanges();

    // bring the element in to view port
   // lastEl.scrollIntoView({ behavior: "smooth", block: "nearest" });
  }

  getNewPage(): HTMLDivElement {
    const page = document.createElement("div");
    page.classList.add("page");
    page.classList.add(this.pageSize);
    return page;
  }
}
    @Directive({
  // tslint:disable-next-line: directive-selector
  selector: "[pageContent]"
})
export class PageContentDirective {

}

Antworten

4 HirenParekh Oct 15 2020 at 13:15

Es geht darum, den angegebenen Inhalt so zu teilen, dass er in die angegebene Seitengröße passt.

Wir können eine Komponente erstellen, die die Teilungsfunktionalität für uns übernimmt. Hier ist eine StackBlitz Demo .

Und hier ist eine kurze Erklärung.

Verwenden Sie den ContentChildrenDekorateur, um die Änderung des Inhalts zu beobachten. Jedes Mal, wenn sich der Inhalt ändert, führen wir die Logik zur Seitenerstellung aus.

import {
  AfterContentInit,
  AfterViewInit,
  Component,
  ContentChildren,
  ElementRef,
  Input,
  OnInit,
  QueryList,
  ViewChild
} from "@angular/core";

@Component({
  selector: "app-paginated-view",
  templateUrl: "paginated-view.component.html",
  styleUrls: ["paginated-view.component.scss"]
})
export class PaginatedViewComponent implements AfterViewInit {
  @Input() pageSize: "A3" | "A4" = "A4";

  @ViewChild("paginatedView") paginatedView: ElementRef<HTMLDivElement>;

  @ViewChild("contentWrapper") contentWrapper: ElementRef<HTMLDivElement>;

  @ContentChildren("pageContent", { read: ElementRef }) elements: QueryList<
    ElementRef
  >;

  constructor() {}

  ngAfterViewInit(): void {
    this.updatePages();

    // when ever childs updated call the updatePagesfunction
    this.elements.changes.subscribe(el => {
      this.updatePages();
    });
  }

  updatePages(): void {
    // clear paginated view
    this.paginatedView.nativeElement.innerHTML = "";

    // get a new page and add it to the paginated view
    let page = this.getNewPage();
    this.paginatedView.nativeElement.appendChild(page);

    let lastEl: HTMLElement;
    // add content childrens to the page one by one
    this.elements.forEach(elRef => {
      const el = elRef.nativeElement;

      // if the content child height is larger than the size of the page
      // then do not add it to the page
      if (el.clientHeight > page.clientHeight) {
        return;
      }
      // add the child to the page
      page.appendChild(el);

      // after adding the child if the page scroll hight becomes larger than the page height
      // then get a new page and append the child to the  new page
      if (page.scrollHeight > page.clientHeight) {
        page = this.getNewPage();
        this.paginatedView.nativeElement.appendChild(page);
        page.appendChild(el);
      }
      lastEl = el;
    });

    //bring the element in to view port
    lastEl.scrollIntoView({ behavior: "smooth", block: "nearest" });
  }

  getNewPage(): HTMLDivElement {
    const page = document.createElement("div");
    page.classList.add("page");
    page.classList.add(this.pageSize);
    return page;
  }
}

Wir können diese Komponente in einer solchen Anwendung verwenden.

<app-paginated-view [pageSize]="'A4'">
    <h1 #pageContent>Hello World!!</h1>
    <p #pageContent>This content will be displayed in an A4 size page</p>
</app-paginated-view>

Wir müssen die Vorlagenvariable #pageContent bereitstellen, damit wir sie mit @ContentChildren in unserer PaginnedViewComponent auswählen können.

Beachten Sie, dass wir hier native dom-APIs verwenden, um die dom-Struktur zu ändern. Der Dom-Knoten wird nur von einem Ort an einen anderen verschoben. Wenn Sie also einen Ereignis-Listener hinzugefügt haben oder eine Eigenschaft an die untergeordneten Inhalte gebunden haben, funktionieren diese unverändert.

Edit: Ich habe auch deinen Stackblitz aktualisierthttps://stackblitz.com/edit/angular-ivy-zjf8rv

5 VươngHữuThiện Oct 09 2020 at 06:05

In der Datei app.component.html:

<div class="page" *ngFor="let page of pages; index as i"
  [style.height]="sizePage.height + 'cm'"
  [style.width]="sizePage.width + 'cm'"
  (click)="clickPage(i)">
  <div class="content" 
    [style.paddingTop]="paddingPage.top + 'cm'"
    [style.paddingRight]="paddingPage.right + 'cm'"
    [style.paddingBottom]="paddingPage.bottom + 'cm'"
    [style.paddingLeft]="paddingPage.left + 'cm'"  
    [id]="'content-' + i" contenteditable="true"
    (input)="inputContent($event['data'], i)">
  </div>
</div>

In der Datei app.component.css:

.page {
    background: white;
    display: block;
    margin: 40px auto;
    box-shadow: 0 0 0.5cm rgba(0, 0, 0, 0.5);
    box-sizing: border-box;
}
.page .content {
    overflow: auto;
    outline: 0;
}

In der Datei app.component.ts:

import { AfterViewChecked, Component } from '@angular/core';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent implements AfterViewChecked {
  
  sizePage = {
    width: 21, //cm
    height: 29.7 //cm
  }
  paddingPage = {
    top: 2, //cm
    right: 2, //cm
    bottom: 2, //cm
    left: 2 //cm
  }
  pages = [
    {
      htmlContent: null,
      full: false
    },
  ]
  currentPage = 0;
  currentChar = null;

  runAfterViewChecked = false;
  
  clickPage(i) {
    this.currentPage = i;
  }

  inputContent(char, i) {
    var element = document.getElementById('content-' + i)
    var heightContent = element.offsetHeight * 2.54 / 96; // Convert pixels to cm
    this.pages[i].htmlContent = element.innerHTML;
    console.log(this.pages);
    if (Number(heightContent.toFixed(1)) > this.sizePage.height) { 
      this.currentChar = char;
      this.pages[i].full = true;
      if (!this.pages[i + 1]) {
        this.pages.push({
          htmlContent: null,
          full: false
        })
      }
      this.currentPage = i + 1;
      this.runAfterViewChecked = true;
    }
  }

  ngAfterViewChecked() {
    document.getElementById('content-' + this.currentPage).focus();
    if (this.runAfterViewChecked) {
      if (this.currentChar) {
        var str = this.pages[this.currentPage-1].htmlContent;
        var indexLastCloseDiv = str.lastIndexOf("</div>");
        var indexLastBr = str.lastIndexOf("<br>");
        var lastChar = str[indexLastCloseDiv-1];
        if (indexLastBr != -1 && (indexLastBr + 4) == indexLastCloseDiv)
          lastChar = ' ';

        if (indexLastCloseDiv != -1)
          str = str.slice(0, indexLastCloseDiv-1) + str.slice(indexLastCloseDiv);
        else 
          str = str.slice(0, str.length - 1);
        this.pages[this.currentPage-1].htmlContent = str;

        if (this.pages[this.currentPage].htmlContent)
          this.pages[this.currentPage].htmlContent = lastChar + this.pages[this.currentPage].htmlContent;
        else
          this.pages[this.currentPage].htmlContent = lastChar;
      }

      var element = null;
      for (let i = 0; i < this.pages.length; i++) {
        element = document.getElementById('content-' + i);
        element.innerHTML = this.pages[i].htmlContent;
      }
      this.runAfterViewChecked = false;
    }
  }
}

Link zu Stackblitz

Hier ist ein einfaches Beispiel. Es gibt einige Fehler, bitte geben Sie Ihre Vorschläge für die weitere Entwicklung.

Einige Funktionen wie Rücktaste, Löschen, Seite skalieren, ... wurden nicht verarbeitet.

2 KasraHabibbeygi Oct 08 2020 at 11:11

Wenn Sie HTML A4 wie Office Word A4 erstellen möchten, müssen Sie folgende Größe verwenden:

body{
 width: 21cm ;
 height: 29.7cm;
 margin:30mm 45mm 30mm 45mm;}
1 ErgiKodra Oct 02 2020 at 08:54

Es wäre ziemlich einfach, den Webbrowser zu zwingen, die Seite mit den gleichen Pixelabmessungen wie A4 anzuzeigen. Es kann jedoch einige Macken geben, wenn Dinge gerendert werden.

Angenommen, Ihre Monitore zeigen 72 dpi an, könnten Sie Folgendes hinzufügen:

<!DOCTYPE html>
<html>
  <head>
    <style>
    body {
        height: 842px;
        width: 595px;
        /* to centre page on screen*/
        margin-left: auto;
        margin-right: auto;
    }
    </style>
  </head>
  <body>
  </body>
</html>

Hier ein Beispiel in Ihrem Code mit druckbarem A4-Format: https://stackblitz.com/edit/angular-ivy-fjhpdu?embed=1&file=src/app/app.component.html

1 johnSmith Oct 02 2020 at 08:50

Eigentlich kann ich keine JS oder CSS von Ihnen sehen, die versuchen, das Problem zu lösen.

Wenn Sie sich jedoch das bereitgestellte Beispiel von xing ansehen, verwenden sie die statische Pixelbreite / -höhe

width: 595px;
height: 842px;

Dies entspricht einem PPI (Pixel pro Zoll) von 72 für das angegebene Format A4, was das einzig Wichtige ist.

Wenn Sie das wissen, können Sie beim Bearbeiten einfach überprüfen, ob diese Höhe überschritten wird, und das DOM entsprechend bearbeiten ("Neue Seite erstellen", "Elemente oder Teile teilen / verschieben" usw. ...). Sie sollten jetzt alles haben, um sich selbst zu lösen. Erwarten Sie jedoch, dass viel Zeit dafür aufgewendet wird, insbesondere, wenn es darum geht, Schriftgrößen / Rendering / Druckanpassung beizubehalten und nicht über die mobile Version zu sprechen;)

Viel Glück

1 VươngHữuThiện Oct 14 2020 at 14:35

In der Datei app.component.html:

<div class="container" id="container"></div>
<button type="button" class="buttonAdd" (click)="addBlock()">Add Block</button>

In der Datei app.component.scss:

.buttonAdd {
    position: fixed;
    display: inline-block;
    font-weight: 400;
    text-align: center;
    white-space: nowrap;
    vertical-align: middle;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    border: 1px solid transparent;
    transition: color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;
    color: #fff;
    background-color: #007bff;
    border-color: #007bff;
    padding: .25rem .5rem;
    font-size: .875rem;
    line-height: 1.5;
    border-radius: .2rem;
    top: 0;
}
.container {
    height: 100%;
    width: 100%;
}
.page {
    // background: white;
    display: block;
    margin: 40px auto;
    box-shadow: 0 0 0.5cm rgba(0, 0, 0, 0.5);
    box-sizing: border-box;
    .content {
        overflow: auto;
        outline: 0;
        .block {
            border: 1px solid rgba(0,0,0,0);
            padding: .25rem;
            cursor: default;
            &:hover {
                border: 1px solid #dee2e6;
                border-radius: .25rem;
            }
            .title {
                font-weight: bold;
            }
            .value {
                cursor: text;
            }
        }
    }
}

In der Datei app.component.ts:

import { AfterViewInit, Component, ElementRef, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'], 
  encapsulation: ViewEncapsulation.None,
})
export class AppComponent implements OnInit, AfterViewInit, OnDestroy {
  sizePage = {
    width: 21, //cm
    height: 29.7 //cm
  }
  paddingPage = {
    top: 2, //cm
    right: 2, //cm
    bottom: 2, //cm
    left: 2 //cm
  }

  data = [
    {
      title: "Name_1",
      value: "Thomas K.Wilson"
    }, {
      title: "Email_1",
      value: "[email protected]"
    }, {
      title: "Telephone_1",
      value: "0123 456 789"
    }, {
      title: "Job_1",
      value: "Teacher"
    }, {
      title: "Name_2",
      value: "Thomas K.Wilson"
    }, {
      title: "Email_2",
      value: "[email protected]"
    }, {
      title: "Telephone_2",
      value: "0123 456 789"
    }, {
      title: "Job_2",
      value: "Teacher"
    }, {
      title: "Name_3",
      value: "Thomas K.Wilson"
    }, {
      title: "Email_3",
      value: "[email protected]"
    }, {
      title: "Telephone_3",
      value: "0123 456 789"
    }, {
      title: "Job_3",
      value: "Teacher"
    }, {
      title: "Name_4",
      value: "Thomas K.Wilson"
    }, {
      title: "Email_4",
      value: "[email protected]"
    }, {
      title: "Telephone_4",
      value: "0123 456 789"
    }, {
      title: "Job_4",
      value: "Teacher"
    }, {
      title: "Name_5",
      value: "Thomas K.Wilson"
    }, {
      title: "Email_5",
      value: "[email protected]"
    }, {
      title: "Telephone_5",
      value: "0123 456 789"
    }, {
      title: "Job_5",
      value: "Teacher"
    }, {
      title: "Name_6",
      value: "Thomas K.Wilson"
    }, {
      title: "Email_6",
      value: "[email protected]"
    }, {
      title: "Telephone_6",
      value: "0123 456 789"
    }, {
      title: "Job_6",
      value: "Teacher"
    }, {
      title: "Name_7",
      value: "Thomas K.Wilson"
    }, {
      title: "Email_7",
      value: "[email protected]"
    }, {
      title: "Telephone_7",
      value: "0123 456 789"
    }, {
      title: "Job_7",
      value: "Teacher"
    }, {
      title: "Name_8",
      value: "Thomas K.Wilson"
    }, {
      title: "Email_8",
      value: "[email protected]"
    }, {
      title: "Telephone_8",
      value: "0123 456 789"
    }, {
      title: "Job_8",
      value: "Teacher"
    }, {
      title: "Name_9",
      value: "Thomas K.Wilson"
    }, {
      title: "Email_9",
      value: "[email protected]"
    }, {
      title: "Telephone_9",
      value: "0123 456 789"
    }, {
      title: "Job_9",
      value: "Teacher"
    }, {
      title: "Name_10",
      value: "Thomas K.Wilson"
    }, {
      title: "Email_10",
      value: "[email protected]"
    }, {
      title: "Telephone_10",
      value: "0123 456 789"
    }, {
      title: "Job_10",
      value: "Teacher"
    }
  ]

  heightPageWithoutPadding = this.convertCmtoPx(this.sizePage.height - (this.paddingPage.top + this.paddingPage.bottom));
  elContainer;
  anchorsBlockValue;
  pageContent = [[]]; // Ex: [[0, 1, 2, 3], [4, 5]]

  constructor (private elementRef: ElementRef){

  }
  
  ngOnInit() {
    
  }

  ngAfterViewInit() {
    this.elContainer = document.getElementById('container');
    this.elContainer.innerHTML += this.createHTMLPage(0);
    this.insertListData();
    this.anchorsBlockValue = this.elementRef.nativeElement.querySelectorAll('.block .value');
    this.anchorsBlockValue.forEach((anchor: HTMLAnchorElement) => {
      anchor.addEventListener('input', this.handleAnchorBlockValue)
    });
  }

  insertListData() {
    var html_ListBlock = "";
    var html_Block = "";
    var iPage = 0;
    var iBlock = 0;
    var elPageContent = document.getElementById('page-' + iPage + '-content');
    for (let i = 0; i < this.data.length; i++) {
      
      html_Block = this.createHTMLBlock(iPage, iBlock, this.data[i]);
      elPageContent.innerHTML = html_ListBlock + html_Block; 

      if (elPageContent.offsetHeight > this.heightPageWithoutPadding) {
        elPageContent.innerHTML = html_ListBlock;

        iPage += 1;
        this.elContainer.innerHTML += this.createHTMLPage(iPage);
        elPageContent = document.getElementById('page-' + iPage + '-content'); 
        
        this.pageContent[iPage] = [];
        this.pageContent[iPage].push(iBlock);

        html_Block = this.createHTMLBlock(iPage, iBlock, this.data[i]);
        html_ListBlock = html_Block;
        elPageContent.innerHTML = html_ListBlock;
      } else {
        this.pageContent[iPage].push(iBlock);
        
        html_ListBlock += html_Block;
        elPageContent.innerHTML = html_ListBlock;
      }
      iBlock += 1;
    }
    // nodes += `<button type="button" class="buttonAdd" (click)="addBlock()">Add Block</button>`;
  }

  handleAnchorBlockValue = (event: Event) => {
    // Prevent opening anchors the default way
    event.preventDefault();
    const anchor = event.target as HTMLAnchorElement;
    const id_anchorParentEl = anchor.parentElement.getAttribute('id'); // page-iPage-content-block-iBlock
    var iPage = Number(id_anchorParentEl.slice(id_anchorParentEl.indexOf("page-") + ("page-").length, id_anchorParentEl.indexOf("-content")));
    var iBlock = Number(id_anchorParentEl.slice(id_anchorParentEl.indexOf("block-") + ("block-").length, id_anchorParentEl.length));
    var elPageContent = anchor.parentElement.parentElement;
    if (elPageContent.offsetHeight > this.heightPageWithoutPadding) {
      if (!this.pageContent[iPage + 1]) {
        this.elContainer.innerHTML += this.createHTMLPage(iPage + 1);
        this.pageContent[iPage + 1] = [];
      }
      if (this.pageContent[iPage].length == 1) {
        // This is (Height Block == Height Content) > Height Page
        alert("To be continue ...");
      } else {
        while (iPage < this.pageContent.length) {

          var elPageContent = document.getElementById('page-' + iPage + '-content'); 
          var iLastBlock_PageContent = this.pageContent[iPage][this.pageContent[iPage].length - 1];
          var elLastBlock_PageContent = document.getElementById('page-' + iPage + '-content-block-' + iLastBlock_PageContent); 
          elLastBlock_PageContent.remove();
          this.pageContent[iPage].pop();
    
          if (!this.pageContent[iPage + 1]) {
            this.elContainer.innerHTML += this.createHTMLPage(iPage + 1);
            this.pageContent[iPage + 1] = [];
          }

          elLastBlock_PageContent.setAttribute('id', 'page-' + (iPage + 1) + '-content-block-' + iLastBlock_PageContent); 
          var elNextPageContent = document.getElementById('page-' + (iPage + 1) + '-content'); 
          elNextPageContent.innerHTML = elLastBlock_PageContent.outerHTML + elNextPageContent.innerHTML;
          this.pageContent[iPage + 1].unshift(iLastBlock_PageContent);
    
          if (elPageContent.offsetHeight <= this.heightPageWithoutPadding) {
            if (elNextPageContent.offsetHeight <= this.heightPageWithoutPadding) {
              break;
            } else {
              iPage += 1;
            }
          }
        }
      }
      this.anchorsBlockValue = this.elementRef.nativeElement.querySelectorAll('.block .value');
      this.anchorsBlockValue.forEach((anchor: HTMLAnchorElement) => {
        anchor.addEventListener('input', this.handleAnchorBlockValue)
      });
    }
  }

  addBlock() {
    alert("To be continue ...");
  }

  convertPxToCm(px) {
    return Math.round(px * 2.54/96 * 100) / 100;
  }

  convertCmtoPx(cm) {
    return Math.round(cm * 96/2.54);
  }

  createHTMLBlock(iPage, iBlock, data) {
    return `<div class="block" id="page-${iPage}-content-block-${iBlock}">
              <div class="title">${data.title}</div> <div class="value" contenteditable>${data.value}</div>
            </div>`;
  }

  createHTMLPage(iPage) {
    return `<div class="page" id="page-${iPage}" style=" height: ${this.sizePage.height}cm;
                width: ${this.sizePage.width}cm; padding-top: ${this.paddingPage.top}cm;
                padding-right: ${this.paddingPage.right}cm; padding-bottom: ${this.paddingPage.bottom}cm;
                padding-left: ${this.paddingPage.left}cm; "> <div class="content" id="page-${iPage}-content">
              </div>
            </div>`;
  }

  ngOnDestroy() {
    // Cleanup by removing the event listeners on destroy
    this.anchorsBlockValue.forEach((anchor: HTMLAnchorElement) => {
      anchor.removeEventListener('input', this.handleAnchorBlockValue)
    })
  }
}

In der Datei tsconfig.json:

Hinzufügen

"resolveJsonModule": true,
"allowSyntheticDefaultImports": true,
"esModuleInterop": true

Es sieht aus wie das

{
  "compileOnSave": false,
  "compilerOptions": {
    "baseUrl": "./",
    "outDir": "./dist/out-tsc",
    "sourceMap": true,
    "declaration": false,
    "downlevelIteration": true,
    "experimentalDecorators": true,
    "module": "esnext",
    "moduleResolution": "node",
    "importHelpers": true,
    "target": "es2015",
    "typeRoots": [
      "node_modules/@types"
    ],
    "lib": [
      "es2018",
      "dom"
    ],
    "resolveJsonModule": true,
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true
  },
  "angularCompilerOptions": {
    "enableIvy": true,
    "fullTemplateTypeCheck": true,
    "strictInjectionParameters": true
  }
}

Link zu Stackblitz

Ich habe das getan, nachdem ich mir Xings Lebenslaufseite angesehen hatte.

Dieses Block- und Datentyp-Design erleichtert das Trennen von Spalten für die Seite und das Hinzufügen von Inhalten mit beliebigen Überschriften.

Sie müssen Ihre Daten in meinen Datentyp konvertieren, indem Sie die Funktion dataConvert in ngOnInit () hinzufügen.

Weil Sie den Datentyp Text verwenden. Wenn es vielfältiger wäre, wäre der Datentyp:

data = [
    {
      type: "Text",
      title: "Full Name",
      value: "Thomas K.Wilson"
    }, {
      type: "Image",
      title: "My Avatar",
      value: "linkImage.com"
    }
]
Ravi Oct 09 2020 at 05:39

Wenn Sie glauben, dass Sie dies mit jquery tun können, gibt es keine Einschränkung für die Verwendung von jquery in Angular

Sie müssten folgende Pakete hinzufügen

jQuery (Für jquery natürlich)https://www.npmjs.com/package/jquery

@ types / jquery (zur Unterstützung in Typoskript)https://www.npmjs.com/package/@types/jquery

Im Folgenden finden Sie Informationen zur Verwendung in Ihrer ts-Datei (nur zum Beispiel).

import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
declare var $: any; @Component({ selector: 'app-a4', templateUrl: './a4.component.html', styleUrls: ['./a4.component.css'] }) export class A4Component implements OnInit { max_pages = 5; page_count = 0; constructor() { } ngOnInit(): void { this.snipMe(); } snipMe() { this.page_count++; if (this.page_count > this.max_pages) { return; } var long = $(this)[0].scrollHeight - Math.ceil($(this).innerHeight()); var children = $(this).children().toArray();
    var removed = [];
    while (long > 0 && children.length > 0) {
      var child = children.pop();
      $(child).detach(); removed.unshift(child); long = $(this)[0].scrollHeight - Math.ceil($(this).innerHeight()); } if (removed.length > 0) { var a4 = $('<div class="A4"></div>');
      a4.append(removed);
      $(this).after(a4);
      this.snipMe.call(a4[0]);
    }
  }
}