I'm familiar with generating PDFs using a "Bot". However I need to print the document very quickly so syncing to trigger the "create a new file" step that renders pdfs and pops 'em in a file store ends up being a little to slow or temporally inconsistent. I don't really want to store them anyway since the data is fairly dynamic - i'd rather render them when needed. I'm wondering what solutions there might be.
One option I was considering was making a webpage that renders the document from information contained in the URI. This way I just have to generate a link and it opens in the browser.
Another way would be sending the data in the JSON body of an outbound webhook / API call, but I think automations don't trigger til sync right?
There must be some better ways I haven't quite understood from my research. Maybe someone can explain it in a way I will understand.
Anyway, what I want to do is generate a label and print it almost instantly after a form is completed. Bonus points if I can select the printer and print details within appsheets or print automatically on form save.
Solved! Go to Solution.
For those who are interested I finally made that “instant print” thing...
I made a quick react app (use npx create-react-app or vite).
Uses React Router's "useSearchParams" to grab the URI query parameters and plop their value in the component's fields, generating a label with a QR code.
Once rendered, window.print() opens the print dialog.
//Test URI: lotlabel?lotId=dHVhjE7f28cJ3NNNB27Dsu&sku=PAINT0016&jobName=GARD%2010574&jobId=23717&release=1of1&kit=23717-R1-K1
import { useSearchParams } from "react-router-dom";
import { useEffect } from "react";
import QRCode from "react-qr-code";
function LotLabel() {
let [searchParams] = useSearchParams();
const allParams = {};
for (const [key, value] of searchParams.entries()) {
allParams[key] = value;
}
const { lotId, sku, jobName, jobId, release, kit } = allParams;
useEffect(() => {
window.print();
}, []);
return (
<div className="label">
<div className="lot-info">
<p>BMP SKU:</p>
<h1>{sku}</h1>
<h3>
Lot ID: <i>{lotId}</i>
</h3>
<QRCode size={512} value={lotId} level={"H"} />
</div>
{jobId && (
<div className="job-info">
<p>
Job Name: <b>{jobName}</b>
</p>
<p>
Job ID: <b>{jobId}</b>
</p>
<p>
Release: <b>{release}</b>
</p>
<p>
Kit: <b>{kit}</b>
</p>
</div>
)}
</div>
);
}
export default LotLabel;
Over in my AppSheet app, my Item page has a 'dynamic' link action button.
CONCATENATE(
"https://labelprinter-cra.vercel.app/lotLabel?lotId=",[Lot ID],
IF(ISNOTBLANK([SKU]),CONCATENATE("&sku=",[SKU]),""),
IF(ISNOTBLANK([Job Name]),CONCATENATE("&jobName=",[Job Name]),""),
IF(ISNOTBLANK([Job ID]),CONCATENATE("&jobId=",[Job ID]), ""),
IF(ISNOTBLANK([Release]),
CONCATENATE("&release=",[Release].[Release Number],"of",[Job ID].[Total Releases]),
""
),
IF(ISNOTBLANK([Kit ID]),CONCATENATE("&kit=",[Kit ID]),"")
)
With this I can render the document right when I make a change; without syncing!
Keep in mind this is a pretty limited use-case. URIs have a character limit. But you could do some stuff with a database and webhooks if you needed to pull more information (though at that point you might as well make a webapp).
I guess you could do it in raw js/html too with
document.addEventListener('DOMContentLoaded', function() {
const params = new URLqueryParams(window.location.search);
const lotID = params.get('lotId')
populateDocument(lotId)
window.print();
}
function populateDocument(lotID) {
document.getElementById('lotId').textContent = `Lot ID: ${lotID}`;
}
or whatever it would be.
Is the problem that your app takes 30+ seconds to load?
___________________________________________________________________________________
Ultimately I feel like you're going to face the same problem no matter what:
I'm working on using the "External Go to a Website" action.
The URI contains the relevant data from the row in query parameters.
CONCATENATE("www.mySite.com/print?name=",[Name],"&reason=",[Reason])
In the browser, the site renders a simple html page with the values from the query params, i.e.
<h1>1</h1><p>My Fake Name</p>
This will be cool. Do you mind sharing further details. I had in my mind to do something like this to generate a PDF from data in a Data URI format using Node.js. This process typically involves converting the Data URI to a buffer and then using a PDF library in Node.js to create the PDF.
So, about that PDF generating problem with AppSheet - it's just way too slow, especially when there's a bunch of bots in the mix. It seriously feels like it takes forever to get one measly PDF created. I mean, we're living in a world where AI can whip up videos in seconds, and here we are waiting ages for a simple document. It's a total disaster, especially when you think about how AppSheet could step up their game and fix this issue. Come on, AppSheet team, we're counting on you to tackle these real-life problems!
For those who are interested I finally made that “instant print” thing...
I made a quick react app (use npx create-react-app or vite).
Uses React Router's "useSearchParams" to grab the URI query parameters and plop their value in the component's fields, generating a label with a QR code.
Once rendered, window.print() opens the print dialog.
//Test URI: lotlabel?lotId=dHVhjE7f28cJ3NNNB27Dsu&sku=PAINT0016&jobName=GARD%2010574&jobId=23717&release=1of1&kit=23717-R1-K1
import { useSearchParams } from "react-router-dom";
import { useEffect } from "react";
import QRCode from "react-qr-code";
function LotLabel() {
let [searchParams] = useSearchParams();
const allParams = {};
for (const [key, value] of searchParams.entries()) {
allParams[key] = value;
}
const { lotId, sku, jobName, jobId, release, kit } = allParams;
useEffect(() => {
window.print();
}, []);
return (
<div className="label">
<div className="lot-info">
<p>BMP SKU:</p>
<h1>{sku}</h1>
<h3>
Lot ID: <i>{lotId}</i>
</h3>
<QRCode size={512} value={lotId} level={"H"} />
</div>
{jobId && (
<div className="job-info">
<p>
Job Name: <b>{jobName}</b>
</p>
<p>
Job ID: <b>{jobId}</b>
</p>
<p>
Release: <b>{release}</b>
</p>
<p>
Kit: <b>{kit}</b>
</p>
</div>
)}
</div>
);
}
export default LotLabel;
Over in my AppSheet app, my Item page has a 'dynamic' link action button.
CONCATENATE(
"https://labelprinter-cra.vercel.app/lotLabel?lotId=",[Lot ID],
IF(ISNOTBLANK([SKU]),CONCATENATE("&sku=",[SKU]),""),
IF(ISNOTBLANK([Job Name]),CONCATENATE("&jobName=",[Job Name]),""),
IF(ISNOTBLANK([Job ID]),CONCATENATE("&jobId=",[Job ID]), ""),
IF(ISNOTBLANK([Release]),
CONCATENATE("&release=",[Release].[Release Number],"of",[Job ID].[Total Releases]),
""
),
IF(ISNOTBLANK([Kit ID]),CONCATENATE("&kit=",[Kit ID]),"")
)
With this I can render the document right when I make a change; without syncing!
Keep in mind this is a pretty limited use-case. URIs have a character limit. But you could do some stuff with a database and webhooks if you needed to pull more information (though at that point you might as well make a webapp).
I guess you could do it in raw js/html too with
document.addEventListener('DOMContentLoaded', function() {
const params = new URLqueryParams(window.location.search);
const lotID = params.get('lotId')
populateDocument(lotId)
window.print();
}
function populateDocument(lotID) {
document.getElementById('lotId').textContent = `Lot ID: ${lotID}`;
}
or whatever it would be.
Good one ! Did you manage to achieve using child rows. For example invoice with multiple line items ?
as long as you kept the url under 2000 characters you could do that. alternatively i the child rows were already synced you could send some kind of shorthand reference and grab that part of things from your data-source.
Thanks @generativegeorg. You might want to put this in Tips & Tricks.
Hi bro,
I request your kind attention here.
1. Could you please share here the printed output ? i mean the pics of the label which you have done .
2. In 2nd para you have mentioned that you have using custom url that brings the necessary content in browser .
2.1 does the webpage opens in the app sheet or externally ? Do you have any screenshot for reference ?
2.2 Have you done it through HTML ?
3. You have used some API, web hooks... that everything functions inside the device (mobile, desktop) or it connects the server and get backs with file ?
4. Could you please share the demo app which you have created ? The sample which you have given connects with github . I need see in appsheet app.
Please help I having a case that is almost similar to your post.
Table printing is possible in URL method?
User | Count |
---|---|
33 | |
31 | |
30 | |
19 | |
18 |