Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

print multiple components in .map #323

Closed
Fatdrfrog opened this issue Dec 2, 2020 · 12 comments
Closed

print multiple components in .map #323

Fatdrfrog opened this issue Dec 2, 2020 · 12 comments
Labels

Comments

@Fatdrfrog
Copy link

Hi!

I'm trying to print multiple barcodes in map. If I will print them by passing an array inside ComponentToPrint as a prop, and then map inside, it's going to work well and display in the browser all needed elements. But I want to map before, by not sending it inside as a prop. like array.map((e) =>{ComponentToPrint}).
Here is sandbox that doesn't work as I am expecting: https://codesandbox.io/s/elated-aryabhata-ub5zu?file=/src/App.js.
Thanks in advance)

@MatthewHerbst
Copy link
Owner

MatthewHerbst commented Dec 2, 2020

Hello! So, you would need to create a new ref for each component. Right now you create a single ref, and then in every iteration of the map it gets overwritten, meaning when the loop is finished the ref just points to the last element in the loop. You could solve this by moving the loop to the parent component.

I will say that having multiple react-to-print components firing from a single event is unhandled behavior, and I'm not sure what will happen. What I think will happen is that each one will print serially, so, you click your button and the first one opens the print dialog, then when you print/cancel that the next one opens the print dialog, etc

@Fatdrfrog
Copy link
Author

Thank you @MatthewHerbst! I think I will just leave it as map through each element inside ComponentToPrint.

@el2king
Copy link

el2king commented Sep 7, 2021

Is there an example where @MatthewHerbst is proposing actually works? I am trying to print multiple components using .map, but I can also get the first element to be part of the print preview, and not all elements. Any examples would be nice, thanks!

@MatthewHerbst
Copy link
Owner

@el2king if you can provide some code or ideally a codesandbox I'd be happy to help walk you through it

@el2king
Copy link

el2king commented Sep 9, 2021

I actually figured this out, so I'm good for this, but I have another problem in regards to ShadowDOM, and I see an issue related to this (#176), so I'll add a comment there.

@Dmitriy-Krivetsky
Copy link

Dmitriy-Krivetsky commented Oct 19, 2021

I solved my problem by combining several components into one, and then sending it to print

const handlePrint = useReactToPrint({
   content: () => {
      const tableStat = tableStatRef.current.cloneNode(true);
      const PrintElem = document.createElement('div');
      const statElem = <span>Text</span>;
      PrintElem.innerHTML = statElem;
      PrintElem.appendChild(tableStat);
      return PrintElem;
    },
});

@MatthewHerbst
Copy link
Owner

I'll add a tip about this to the README since multiple people are running into it, thanks all for letting me know

MatthewHerbst added a commit that referenced this issue Oct 20, 2021
* Add `logMessages` function, fix small bug

* Style examples, add example using functional component to print

* Added style tip about page orientation

* Added functional ComponentToPrint example, added a styling pitfall

* Add pitfall example regarding printing component arrays (#323)

* Upgrade all `devDependencies`

* Change class-only error to link how to use functional components

* Fix print to PDF filename not working in all major browsers

#391

* Add to README about known issues when printing from mobile WebViews
@ratrateroo
Copy link

ratrateroo commented Dec 6, 2021

I tried to combine solutions for creating references to map elements for the bug of react-to-print

import React, { useRef, useEffect } from 'react';
import ReactToPrint from 'react-to-print';
import ComponentToPrint from './ComponentToPrint';
// props content : items = [1, 2, 3, 4, 5, 6];
const Items = (props) => {
	const itemsRef = useRef([]);
	useEffect(() => {
		itemsRef.current = itemsRef.current.slice(0, props.items.length);
	}, [props.items]);
	return props.items.map((el, i) => (
		<div
			key={i}
			style={{
				background: 'yellowgreen',
			}}>
			<ReactToPrint
				trigger={() => (
					<button
						style={{
							background: 'blue',
						}}>
						Print {el}
					</button>
				)}
				content={() => {
					return itemsRef.current[i];
				}}
			/>
			<div style={{ display: 'none' }}>
				<ComponentToPrint
					ref={(el) => (itemsRef.current[i] = el)}
					number={el}
				/>
			</div>
		</div>
	));
};
export default Items;

@MatthewHerbst
Copy link
Owner

Hi @ratrateroo did you get your solution to work? I've never seen multiple refs saved into an array before, but if that works it's good to know! To be clear, there is no bug, it's just an edge case that requires special handling. I don't think the useEffect you have in your example above is necessary.

@ratrateroo
Copy link

ratrateroo commented Dec 7, 2021 via email

@stiwari99
Copy link

stiwari99 commented Dec 8, 2021

Here is working code for printing each component on separate page

https://codesandbox.io/s/brave-pine-4wncd?file=/src/ComponentToPrintSVG.js

import React from "react";
import Barcode from "react-barcode";
import styled from "styled-components";

const PageBreakWrapper = styled.div`
  && {
    page-break-after: always;
  }
`;

const PrintTemplate = ({ detail }) => {
  return (
    <div>
      <div>
        <Barcode value={detail.code} /*format="EAN13"*/ />
        <br />
        {detail.name && detail.name.substr(0, 42)}
      </div>
      <PageBreakWrapper>&nbsp;</PageBreakWrapper>
    </div>
  );
};
export default class ComponentToPrintSVG extends React.Component {
  render() {
    let printingPages = [];
    const { details } = this.props;
    for (const detail of details) {
      console.log(detail);
      const tempTemplate = <PrintTemplate detail={detail} />;
      printingPages.push(tempTemplate);
    }

    return (
      <div>
        {/* map and create single component for each page */}
        {printingPages}
      </div>
    );
  }
}

@junior3199
Copy link

junior3199 commented Apr 17, 2023

Here is working code for printing each component on separate page

https://codesandbox.io/s/brave-pine-4wncd?file=/src/ComponentToPrintSVG.js

I'm having this problem in 2023 and this solution works best for meee!!! Thank you! 🥳🥳🥳

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

7 participants