Skip to content

Commit

Permalink
Merge pull request #171 from selemxmn/printService
Browse files Browse the repository at this point in the history
  • Loading branch information
Core121 authored Dec 2, 2023
2 parents b5559ce + 6268b5c commit 0ff7d2d
Show file tree
Hide file tree
Showing 11 changed files with 533 additions and 181 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
# 1.5.0 (2023-11-29)
* Now supports Angular 17
* Added printService

# 1.4.0 (2023-11-29)
* Now supports Angular 16

# 1.3.0 (2022-12-20)
### New features
* Supports previewOnly tag, allowing for the print preview to show without the print dialog
Expand Down
45 changes: 44 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ This directive makes printing your HTML sections smooth and easy in your Angular
| ------------ | ------------ |
| 1.2.1 | 7.0.0 - 14.1.0 |
| 1.3.x | 15.0.0 |
| 1.4.x | 16.0.0 |
| 1.5.x | 17.0.0 |
## Setup

**1-** In your root application folder run:
Expand Down Expand Up @@ -185,9 +187,50 @@ Here some simple styles were added to every `h1` & `h2` tags within the `div` wh
ngxPrint>print</button>

```
## Using NgxPrint as a service
Inject the NgxPrintService in the constructor of your component or service:

```typescript
constructor(private printService: NgxPrintService) { }
```

### Printing a Section
```typescript
import { PrintOptions } from './path-to-your/print-options.model';

printMe() {
const customPrintOptions: PrintOptions = new PrintOptions({
printSectionId: 'print-section',
// Add any other print options as needed
});
this.printService.print(customPrintOptions)
}
```

### Print Options Object
The print options object allows you to specify how the print job should be handled. All of which have default values that you can optionally override, although printSectionId is required. It contains the following properties:
```typescript
printSectionId: string = null;
printTitle: string = null;
useExistingCss: boolean = false;
bodyClass: string = '';
previewOnly: boolean = false;
closeWindow: boolean = true;
printDelay: number = 0;
```

### Setting PrintStyles or StyleSheets
```typescript
// Optional property for css as a key-value pair
this.printService.printStyle = styleSheet;

// Optional property for a css file location
this.printService.styleSheetFile = fileLocation;
```

## Contributors :1st_place_medal:

Huge thanks to: [deeplotia](https://github.com/deeplotia) , [Ben L](https://github.com/broem) , [Gavyn McKenzie](https://github.com/gavmck) , [silenceway](https://github.com/silenceway), [Muhammad Ahsan Ayaz](https://github.com/AhsanAyaz) and to all `ngx-print` users
Huge thanks to: [deeplotia](https://github.com/deeplotia) , [Ben L](https://github.com/broem) , [Gavyn McKenzie](https://github.com/gavmck) , [silenceway](https://github.com/silenceway), [Muhammad Ahsan Ayaz](https://github.com/AhsanAyaz), [Core121](https://github.com/Core121) and to all `ngx-print` users

## Donation

Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ngx-print",
"version": "1.3.1",
"version": "1.5.0",
"description": "Plug n' Play Angular (2++) directive to print your stuff",
"author": "https://github.com/selemxmn/ngx-print/graphs/contributors",
"repository": {
Expand Down
208 changes: 208 additions & 0 deletions src/lib/ngx-print.base.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
import { Injectable } from "@angular/core";
import { PrintOptions } from "./print-options";

@Injectable({
providedIn: 'root'
})
export class PrintBase {

private _printStyle: string[] = [];
private _styleSheetFile: string = '';

//#region Getters and Setters
/**
* Sets the print styles based on the provided values.
*
* @param {Object} values - Key-value pairs representing print styles.
* @protected
*/
protected setPrintStyle(values: { [key: string]: { [key: string]: string } }) {
this._printStyle = [];
for (let key in values) {
if (values.hasOwnProperty(key)) {
this._printStyle.push((key + JSON.stringify(values[key])).replace(/['"]+/g, ''));
}
}
}

/**
*
*
* @returns the string that create the stylesheet which will be injected
* later within <style></style> tag.
*
* -join/replace to transform an array objects to css-styled string
*/
public returnStyleValues() {
return `<style> ${this._printStyle.join(' ').replace(/,/g, ';')} </style>`;
}

/**
* @returns string which contains the link tags containing the css which will
* be injected later within <head></head> tag.
*
*/
private returnStyleSheetLinkTags() {
return this._styleSheetFile;
}

/**
* Sets the style sheet file based on the provided CSS list.
*
* @param {string} cssList - CSS file or list of CSS files.
* @protected
*/
protected setStyleSheetFile(cssList: string) {
let linkTagFn = function (cssFileName) {
return `<link rel="stylesheet" type="text/css" href="${cssFileName}">`;
};

if (cssList.indexOf(',') !== -1) {
const valueArr = cssList.split(',');
this._styleSheetFile = valueArr.map(val => linkTagFn(val)).join('');
} else {
this._styleSheetFile = linkTagFn(cssList);
}
}

//#endregion

//#region Private methods used by PrintBase

/**
* Updates the default values for input elements.
*
* @param {HTMLCollectionOf<HTMLInputElement>} elements - Collection of input elements.
* @private
*/
private updateInputDefaults(elements: HTMLCollectionOf<HTMLInputElement>): void {
for (let i = 0; i < elements.length; i++) {
const element = elements[i];
element['defaultValue'] = element.value;
if (element['checked']) element['defaultChecked'] = true;
}
}

/**
* Updates the default values for select elements.
*
* @param {HTMLCollectionOf<HTMLSelectElement>} elements - Collection of select elements.
* @private
*/
private updateSelectDefaults(elements: HTMLCollectionOf<HTMLSelectElement>): void {
for (let i = 0; i < elements.length; i++) {
const element = elements[i];
const selectedIdx = element.selectedIndex;
const selectedOption: HTMLOptionElement = element.options[selectedIdx];

selectedOption.defaultSelected = true;
}
}

/**
* Updates the default values for textarea elements.
*
* @param {HTMLCollectionOf<HTMLTextAreaElement>} elements - Collection of textarea elements.
* @private
*/
private updateTextAreaDefaults(elements: HTMLCollectionOf<HTMLTextAreaElement>): void {
for (let i = 0; i < elements.length; i++) {
const element = elements[i];
element['defaultValue'] = element.value;
}
}

/**
* Retrieves the HTML content of a specified printing section.
*
* @param {string} printSectionId - Id of the printing section.
* @returns {string | null} - HTML content of the printing section, or null if not found.
* @private
*/
private getHtmlContents(printSectionId: string): string | null {
const printContents = document.getElementById(printSectionId);
if (!printContents) return null;

const inputEls = printContents.getElementsByTagName('input');
const selectEls = printContents.getElementsByTagName('select');
const textAreaEls = printContents.getElementsByTagName('textarea');

this.updateInputDefaults(inputEls);
this.updateSelectDefaults(selectEls);
this.updateTextAreaDefaults(textAreaEls);

return printContents.innerHTML;
}

/**
* Retrieves the HTML content of elements with the specified tag.
*
* @param {keyof HTMLElementTagNameMap} tag - HTML tag name.
* @returns {string} - Concatenated outerHTML of elements with the specified tag.
* @private
*/
private getElementTag(tag: keyof HTMLElementTagNameMap): string {
const html: string[] = [];
const elements = document.getElementsByTagName(tag);
for (let index = 0; index < elements.length; index++) {
html.push(elements[index].outerHTML);
}
return html.join('\r\n');
}
//#endregion


/**
* Prints the specified content using the provided print options.
*
* @param {PrintOptions} printOptions - Options for printing.
* @public
*/
protected print(printOptions: PrintOptions): void {

let styles = '', links = '';
const baseTag = this.getElementTag('base');

if (printOptions.useExistingCss) {
styles = this.getElementTag('style');
links = this.getElementTag('link');
}

const printContents = this.getHtmlContents(printOptions.printSectionId);
if (!printContents) {
// Handle the case where the specified print section is not found.
console.error(`Print section with id ${printOptions.printSectionId} not found.`);
return;
}

const popupWin = window.open("", "_blank", "top=0,left=0,height=auto,width=auto");
popupWin.document.open();
popupWin.document.write(`
<html>
<head>
<title>${printOptions.printTitle ? printOptions.printTitle : ""}</title>
${baseTag}
${this.returnStyleValues()}
${this.returnStyleSheetLinkTags()}
${styles}
${links}
</head>
<body ${printOptions.bodyClass ? `class="${printOptions.bodyClass}"` : ''}>
${printContents}
<script defer>
function triggerPrint(event) {
window.removeEventListener('load', triggerPrint, false);
${printOptions.previewOnly ? '' : `setTimeout(function() {
closeWindow(window.print());
}, ${printOptions.printDelay});`}
}
function closeWindow(){
${printOptions.closeWindow ? 'window.close();' : ''}
}
window.addEventListener('load', triggerPrint, false);
</script>
</body>
</html>`);
popupWin.document.close();
}
}
22 changes: 4 additions & 18 deletions src/lib/ngx-print.directive.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { NgxPrintDirective } from './ngx-print.directive';
<h2><a target="_blank" rel="noopener" href="https://blog.angular.io/">Angular blog</a></h2>
</li>
</ul>
<table border = "1">
<table border="1">
<tr>
<td>Row 1, Column 1</td>
<td>Row 1, Column 2</td>
Expand Down Expand Up @@ -81,18 +81,6 @@ describe('NgxPrintDirective', () => {
it('should test the @Input printStyle', () => {
const directive = new NgxPrintDirective();

// Define styleSheet before using it
const styleSheet = {/* Define your styles here */ };

directive.printStyle = styleSheet;

// Iterate through printStyle and push values to _printStyle
for (const key in directive.printStyle) {
if (directive.printStyle.hasOwnProperty(key)) {
directive._printStyle.push((key + JSON.stringify(directive.printStyle[key])).replace(/['"]+/g, ''));
}
}

// Create a spy on the instance's method
spyOn(directive, 'returnStyleValues').and.callThrough();

Expand All @@ -106,12 +94,10 @@ describe('NgxPrintDirective', () => {

it('should returns a string from array of objects', () => {
const directive = new NgxPrintDirective();
directive._printStyle = [
"h2{border:solid 1px}",
"h1{color:red,border:1px solid}"
];
directive.printStyle = styleSheet;

expect((() => { return directive.returnStyleValues() })()).toEqual('<style> h2{border:solid 1px} h1{color:red;border:1px solid} </style>');
// Ensure the print styles are correctly formatted in the document
expect(directive.returnStyleValues()).toEqual('<style> h2{border:solid 1px} h1{color:red;border:1px solid} </style>');
});

it(`should popup a new window`, () => {
Expand Down
Loading

0 comments on commit 0ff7d2d

Please sign in to comment.