How can i append to PDF file in Node-Red?

I'm looking for solution on how can i append to a pdf file. The output 'file' of HTML-PDF node generate a new file every time i insert new line. The output "buffer" /"stream" save only the first insert. Is it possible to append pdf file in node-red. And thanks in advance.

Maybe you would get some more help if you post your flow here instead of starting a new topic for the same question over and over again.

See How to share code or flow json

1 Like

[{"id":"7a388eef.f3624","type":"tab","label":"Flow 6","disabled":false,"info":""},{"id":"4ce45511.318b7c","type":"ui_template","z":"7a388eef.f3624","group":"1dc1526e.1e610e","name":"","order":0,"width":0,"height":0,"format":"<style>\n /* The Modal (background) */\n body {font-family: Arial, Helvetica, sans-serif;}\n\n /* The Modal (background) */\n .modal {\n display: none; /* Hidden by default */\n position: fixed; /* Stay in place */\n z-index: 1; /* Sit on top */\n padding-top: 100px; /* Location of the box */\n left: 0;\n top: 0;\n width: 100%; /* Full width */\n height: 100%; /* Full height */\n overflow: auto; /* Enable scroll if needed */\n background-color: rgb(0,0,0); /* Fallback color */\n background-color: rgba(0,0,0,0.4); /* Black w/ opacity */\n }\n\n /* Modal Content */\n .modal-content {\n position: relative;\n background-color: #e6e6e6;\n margin: auto;\n padding: 0;\n border: 1px solid #888;\n width: 50%;\n box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19);\n -webkit-animation-name: animatetop;\n -webkit-animation-duration: 0.4s;\n animation-name: animatetop;\n animation-duration: 0.4s\n }\n\n /* Add Animation */\n @-webkit-keyframes animatetop {\n from {top:-300px; opacity:0}\n to {top:0; opacity:1}\n }\n\n @keyframes animatetop {\n from {top:-300px; opacity:0}\n to {top:0; opacity:1}\n }\n\n /* The Close Button */\n .close,.close_f {\n color: #004d66;\n float: right;\n font-size: 28px;\n font-weight: bold;\n }\n\n .close:hover,\n .close_f:hover,\n .close:focus,\n .close_f:focus {\n color: #000;\n text-decoration: none;\n cursor: pointer;\n }\n\n .modal-header {\n padding: 20px 16px;\n background-color: #004d66;\n }\n\n .modal-body {padding: 2px 16px;}\n\n .modal-footer {\n padding: 20px 16px;\n background-color: #004d66;\n }\n#outer\n{\n width:100%;\n text-align: center;\n}\n.inner\n{\n display: inline-block;\n}\n#myBtn1,#myBtn2,#myBtn3,#myBtn4,#myBtn5 {\n background-color: #004d66;\n border: none;\n color: white;\n padding: 15px 32px;\n text-align: center;\n text-decoration: none;\n display: inline-block;\n font-size: 16px;\n margin: 4px 2px;\n cursor: pointer;\n i {\n padding-right: 0.3em;\n }\n}\n\n</style>\n\n<!-- Trigger/Open The Modal -->\n\n<div id=\"outer\">\n <div class=\"inner\"><button class=\"inner\" id=\"myBtn1\">Button1</button></div>\n <div class=\"inner\"><button class=\"inner\" id=\"myBtn2\">Button2</button></div>\n <div class=\"inner\"><button class=\"inner\" id=\"myBtn3\">Button3</button></div>\n <div class=\"inner\"><button class=\"inner\" id=\"myBtn4\">Button4</button></div>\n <div class=\"inner\"><button class=\"inner\" id=\"myBtn5\">Button5</button></div>\n</div>\n<script type=\"text/javascript\">\nvar msg ={};\n\n</script>\n<!-- The Modal -->\n<div id=\"myModal\" class=\"modal\" >\n\n <!-- Modal content -->\n <div class=\"modal-content\">\n <div class=\"modal-header\">\n <span class=\"close\">&times;</span>\n <h2>Saisie votre matricule</h2>\n </div>\n <div class=\"modal-body\">\n <h3>Matricule : </h3> <br>\n <input type=\"number\" ng-model=\"msg.payload.data3\" id=\"matricule\" name=\"matricule\" size=\"100\" min=\"0\"><br><br>\n <button id=\"myBtn_m\">Entrer</button>\n </div>\n <div class=\"modal-footer\">\n</div>\n </div>\n\n</div>\n\n\n<div id=\"myModal_f\" class=\"modal\">\n\n <!-- Modal content -->\n <div class=\"modal-content\">\n <div class=\"modal-header\">\n <span class=\"close_f\">&times;</span>\n <h2>Formulaire</h2><br>\n </div>\n\n <div class=\"modal-body\">\n <h3>Nom :</h3><input type=\"text\" ng-model=\"msg.payload.data1\" id=\"name\" name=\"Nom\" placeholder=\"Nom\" size=\"77\"><br><br>\n <h3>Prenom : </h3><input type=\"text\" ng-model=\"msg.payload.data2\" id=\"prenom\" name=\"Prenom\" placeholder=\"Prenom\" size=\"77\"> <br><br>\n <button id=\"myBtn_f\" ng-click=\"send(msg)\" ng-disabled=\"(msg.payload.data1 == null) || (msg.payload.data2 == null)\">Enregistrer</button>\n</div>\n<div class=\"modal-footer\">\n</div>\n </div>\n\n</div>\n\n<script>\n\n // Get the modal\n\nvar modal = document.getElementById('myModal');\nvar modal_f = document.getElementById('myModal_f');\n\n// Get the button that opens the modal\nvar btn = document.getElementById(\"myBtn1\");\nvar btn_m = document.getElementById(\"myBtn_m\");\nvar btn_f = document.getElementById(\"myBtn_f\");\n\n// Get the <span> element that closes the modal\nvar span = document.getElementsByClassName(\"close\")[0];\nvar span_f = document.getElementsByClassName(\"close_f\")[0];\n\n// When the user clicks on the button, open the modal\nbtn.onclick = function() {\n = \"block\";\n}\nbtn_m.onclick = function() {\n var x = document.getElementById(\"matricule\").value;\n if(x == 0 )\n { alert(\"Entrer votre matricule\");\n return false;\n }\n else{\n = \"none\";\n = \"block\";\n }\n\n}\nbtn_f.onclick = function() {\n = \"none\";\n}\n\n// When the user clicks on <span> (x), close the modal\nspan.onclick = function() {\n = \"none\";\n}\nspan_f.onclick = function() {\n = \"none\";\n}\n\n// When the user clicks anywhere outside of the modal, close it\nwindow.onclick = function(event) {\n if (( == modal)||( == modal_f)) {\n = \"none\";\n = \"none\";\n\n }\n}\n</script>\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":140,"y":200,"wires":[["340811dc.87522e"]]},{"id":"b304bfb.35d634","type":"file","z":"7a388eef.f3624","name":"","filename":"","appendNewline":true,"createDir":true,"overwriteFile":"false","x":690,"y":200,"wires":[[]]},{"id":"51b9730d.3cebec","type":"HTML-PDF","z":"7a388eef.f3624","name":"HTML-PDF","output":"buffer","x":550,"y":200,"wires":[["b304bfb.35d634"]]},{"id":"340811dc.87522e","type":"function","z":"7a388eef.f3624","name":"test","func":"function formatDate(date) {\n var d = new Date(date),\n month = '' + (d.getMonth() + 1),\n day = '' + d.getDate(),\n year = d.getFullYear();\n\n if (month.length < 2) month = '0' + month;\n if (day.length < 2) day = '0' + day;\n\n return [year, month, day].join('_');\n}\n\nvar tempString =formatDate(Date().toString());\n//var tempString1 =\"//\";\n//var tempString1 =\"//A3EMECA/Users/Public/Partage/\";\nvar tempString1 = \"C:\\\\tmp\\\\\";\nvar tempString2 = tempString1.concat(tempString);\nvar finalPath = tempString2.concat(\"_export.pdf\");\nmsg.filename=finalPath;\nreturn msg;","outputs":1,"noerr":0,"x":270,"y":200,"wires":[["dd6ba9ff.3d90a8"]]},{"id":"dd6ba9ff.3d90a8","type":"csv","z":"7a388eef.f3624","name":"","sep":"\\t","hdrin":true,"hdrout":true,"multi":"one","ret":"\\r\\n","temp":"","skip":"2","x":410,"y":200,"wires":[["51b9730d.3cebec"]]},{"id":"1dc1526e.1e610e","type":"ui_group","z":"","name":"","tab":"d683d6f0.5632b8","order":4,"disp":true,"width":"26","collapse":false},{"id":"d683d6f0.5632b8","type":"ui_tab","z":"","name":"Home","icon":"dashboard"}]

Please provide a flow that we can test to see the problem. Use inject node(s) to simulate inputs. I cannot test the one you have provided as it just keeps asking me in French for something and won't accept what I enter.

I'm sorryabout that. Here's an exemple with inject

You have posted a flow with only one node - an inject node. Nothing else.

Sorry again.
[{"id":"95d073fd.2cb84","type":"tab","label":"Flow 18","disabled":false,"info":""},{"id":"d35461.7e881ba","type":"file","z":"95d073fd.2cb84","name":"","filename":"","appendNewline":true,"createDir":true,"overwriteFile":"false","x":550,"y":180,"wires":[[]]},{"id":"185d10ab.0a440f","type":"HTML-PDF","z":"95d073fd.2cb84","name":"HTML-PDF","output":"buffer","x":390,"y":180,"wires":[["d35461.7e881ba"]]},{"id":"a9d1c368.25026","type":"function","z":"95d073fd.2cb84","name":"test","func":"function formatDate(date) {\n var d = new Date(date),\n month = '' + (d.getMonth() + 1),\n day = '' + d.getDate(),\n year = d.getFullYear();\n\n if (month.length < 2) month = '0' + month;\n if (day.length < 2) day = '0' + day;\n\n return [year, month, day].join('_');\n}\n\nvar tempString =formatDate(Date().toString());\n//var tempString1 =\"//\";\n//var tempString1 =\"//A3EMECA/Users/Public/Partage/\";\nvar tempString1 = \"C:\\\\tmp\\\\\";\nvar tempString2 = tempString1.concat(tempString);\nvar finalPath = tempString2.concat(\"_export.pdf\");\nmsg.filename=finalPath;\nreturn msg;","outputs":1,"noerr":0,"x":270,"y":120,"wires":[["185d10ab.0a440f"]]},{"id":"1930847b.b0a68c","type":"inject","z":"95d073fd.2cb84","name":"","topic":"","payload":"100","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":90,"y":80,"wires":[["a9d1c368.25026"]]},{"id":"194d86bf.32fc19","type":"inject","z":"95d073fd.2cb84","name":"","topic":"","payload":"Hi","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":90,"y":160,"wires":[["a9d1c368.25026"]]}]

When I click an inject it creates the file of size 6167 bytes. When I click it again it doubles in size to 12330, and gets bigger each time I click an inject. It is not overwriting the file each time. Have you checked the file size on your system?

yeah i have checed it but the content still the same from the first inject.

What size file are you seeing after one and two injections?

one inject 7 KB , two inject 13 KB.

So you were not right in saying

as the file node is appending to the file each time.
However if you look at the file with a pdf viewer it doesn't show the second part of the file because the pdf node closes the pdf data so the viewer only only shows the part you added the first time. The problem I assume is that the pdf node (node-red-contrib-pdf) expects to write the complete file. To solve your problem you will have to build up the complete set of data that you want to put in the file and then pass it to the pdf node. Unless you can find another node that is which is capable of reading an existing file and adding to it.

Yeah, you are absolutely right Thanks for your time i'll see what i can do and post a solution as soon as possible

When you post your solution, please add it to this thread. Rather than opening a new one... :slight_smile:

1 Like

OK, i will make sure of that

If you're trying to collect data over an unspecified period you should consider to put that data into a database first (sqlite for example) and add a "Generate PDF"-button" which selects the wanted data from the database and writes it to a PDF at once.


Hi again. So i did what @Colin said. i use a function to store the data in array

var dashboardLog = context.get('dashboardLog')|| [];
if(msg.payload != null)

msg = {};
msg.payload = dashboardLog;
return msg;

then i pass all the content in a template node mustache.

> <html>
>     <body>
>         <h1>My Sample Event Attendees</h1>
> {{# payload}}
> * {{data1}} {{data2}} {{data3}}
> <br>
> {{/ payload}}
>     </body>
> </html>

i tried to read and add from an existant pdf file but nothing works for me and i don't think there's a solution for that..:roll_eyes:

Thank you all for help and sorry for asking to many times. :blush:

As I said in your other post, PDF is poorly suited to this purpose.

1 Like

I don't think you are quite following @Colin's logic or understanding why PDF is a bad idea here. As I said in a previous post, Make a PDF file - #3 by drmibell, PDF is a document format, and (with perhaps a very minor exception) it cannot be read or written except as a complete file. @Colin is advising you to save ALL your data and write it as a complete file file for each update. In general, you cannot simply append to a PDF file. Alternatively, you could read the file, extract the content you want, add the new content, and write out the new file. Either way, it's a lot of effort, and I don't see why you would want to do it often.

[EDIT] Apologies for getting "cross-threaded." I just noticed the more recent postings.

1 Like

Is this a cross post of Store data in pdf file by @hathemi