Discussions

 View Only
  • 1.  Automatically save a form page as PDF and insert into attachment field?

    Posted 02-15-2022 16:36
    I've long wondered if there's a solution that's shareable where I could click a button and have a form page automatically saved in PDF format and inserted into an attachment field.  I realize that there are QSPs that provide this service, but I'm more interested in knowing/understanding how to do this myself.

    My impression is that you would need to use JS to write the form to PDF and then encode to base64, and then you could use the base64 result to insert into API_UploadFile.  My JS knowledge is minimal but I can cobble stuff together through StackExchange plus trial and error.  I'm not worried about the API end of things - that seems pretty straight-forward.

    Has anyone tried this themselves that they'd be willing to share? I've looked on the forum before but it seems the answers always fall into, "Hire a QSP," or "Use IOL or some other technique that is now deprecated."  Presumably I'd need to call the JS from a code page?  Or would I need a local API call on my end to launch something?  If it's possible to do everything in QB without having to host something myself, that's obviously the preferable and most portable method, but if that's 100% not possible, I have access to AWS.

    Big picture goal is the user clicks a button, button calls a script that runs through about 20-30 records in a table, uses a specific QB form page to generate a PDF for each record, PDF is uploaded into corresponding record attachment field.  No templates or anything.

    Short of that, clicking the button once per record would also be acceptable, but it would be rad to grab the whole table in one go.


  • 2.  RE: Automatically save a form page as PDF and insert into attachment field?

    Posted 02-15-2022 16:59
    I have need of this function also and so far I've found the same as you.  Interested if anyone has figured out a QB native solution yet.

    ------------------------------
    Jeff Peterson
    ------------------------------



  • 3.  RE: Automatically save a form page as PDF and insert into attachment field?

    Posted 02-17-2022 09:48
    Hey Tyler, 

    I messaged you yesterday and was able to clean it up this morning. This should work for clicking a button and having it save to the original record. I was thinking of working on an idea to loop through and have it save all the records in a table, but haven't gotten to it yet.

    Here is the button, or rich text in my case, formula needed:

    var text usertoken = "enter_user_token_here";
    
    // Enter the form ID to save in myFormID
    var text myReq = "&myDbid=" & Dbid() & "&recId=" & [Record ID#] & "&myFormId=10&usertoken=" & $usertoken;
    
    var text apptoken = "app_token_here";
    
    var text myURL = URLRoot() & "db/" & Dbid() & "?a=API_GetRecordAsHTML&rid=" & [Record ID#] & "dfid=10&apptoken=" & $apptoken;
    
    var text url = URLRoot() & "db/" & AppID() & "?a=dbpage&pageID=10" & "&apptoken=" & $apptoken & $myReq;
    
    
    
    
    "<a class='OpenAsPopup' href=" & $url  & ">Print as HTML</a>"​


    Here is the html page:

    <html>
        <head>
            <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
            <script src="https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.9.2/html2pdf.bundle.js"></script>
        </head>
    
        <body>
            <h1>Record as HTML</h1>
                <p> A Quickbase table embedded in a page of HTML</p>
            <div id="dbPagePayload"></div>
        
    
    
        </body>
        <script src="https://yourRealm.quickbase.com/db/yourAppID?a=dbpage&pageID=YourJSPageID"></script> 
    </html>


    Here is the javascript page:

    let urlParams = new URLSearchParams(window.location.search);
    let dbid = urlParams.get("myDbid");
    let recId = urlParams.get('recId');  
    let myForm = urlParams.get('myFormId');
    let usertoken = urlParams.get('usertoken');
    let apptoken = urlParams.get('apptoken');  
    let root = location.protocol + '//' + location.host;
    let myURL = `${root}/db/${dbid}?a=API_GetRecordAsHTML&rid=${recId}&dfid=${myForm}&apptoken=${apptoken}`;
    let myHostName = "EnterHostName.quickbase.com";
    
    const getURL = () => {
        $.post(myURL, {}, function (response) {
            $("#dbPagePayload").html(response);
        }).then(getDom);
    };
    
    
    
    const getDom = () => {
        let myDoc = document.getElementById("dbFormContainer");
        console.log(myDoc);
        var opt = {
            margin: 1,
            filename: 'myfile.pdf',
            image: { type: 'jpeg', quality: 0.98 },
            html2canvas: { scale: 2 },
            jsPDF: { unit: 'in', format: 'letter', orientation: 'portrait' }
        };
    
        html2pdf().from(myDoc).set(opt).outputPdf('dataurlstring').then(async res => {
          var base64result = res.split(',')[1];
                
          var headers = {
              'QB-Realm-Hostname': myHostName,
              'User-Agent': 'File_Upload',
              'Authorization': `QB-USER-TOKEN ${usertoken}`,
              'Content-Type': 'application/json'
          }
    
    
          // 59 is my attachment field. Replace it with yours.
          body = { "to": dbid, "data": [{"3": {"value": recId}, "59": { "value": { "fileName": "FormPDF.pdf", "data": base64result }}  }], "fieldsToReturn": [ 3, 59 ] }
    
    
          fetch('https://api.quickbase.com/v1/records',
            {
              method: 'POST',
              headers: headers,
              body: JSON.stringify(body)
            })
          .then(async res => {
            if (res.ok) {
              return res.json().then(res => {
                console.log(res)
                window.close()
              });
            }
            return res.json().then(resBody => Promise.reject({status: res.status, ...resBody}));
          })
        .catch(err => console.log(err))
      });
    };
    getURL();
    

    I can admit it is not the prettiest, nor the most optimized solution. But, it works and should get the job done. I will probably work on this in my free time later this week/weekend to have it loop through each record, so I will update this thread when/if I finish.

    ------------------------------
    Sean Connaughton
    ------------------------------



  • 4.  RE: Automatically save a form page as PDF and insert into attachment field?

    Posted 02-17-2022 10:03
    Very cool! Thanks for working on this, Sean. I'm going to try this out as soon as I get the chance.


  • 5.  RE: Automatically save a form page as PDF and insert into attachment field?

    Posted 02-18-2022 15:39
    Like I said before, this isn't the prettiest, but it worked for me! This should loop through and save each form within the range you enter in the popup.

    Formula Rich-Text Field:
    var text usertoken = "enter_user_token_here";
    
    // Enter the form ID to save in myFormID
    var text myReq = "&myDbid=" & Dbid() & "&recId=" & [Record ID#] & "&myFormId=10&usertoken=" & $usertoken;
    
    var text apptoken = "app_token_here";
    
    var text url = URLRoot() & "db/" & AppID() & "?a=dbpage&pageID=10" & "&apptoken=" & $apptoken & $myReq;
    
    "<a class='OpenAsPopup' href='" & $url & "'data-height=600 data-width=600>Print as HTML</a>"​

    HTML:
    <html>
        <head>
            <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
            <script src="https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.9.2/html2pdf.bundle.js"></script>
        </head>
    
        <body>
            <h1>Saving Forms as PDF</h1>
                <p>Records will populate below when completed.</p>
                <p>Depending on the size, it may take longer than expected to start. Check the console for more details.</p>
            <div id="dbPagePayload"></div>
        
    
    
        </body>
        <script src="https://yourRealm.quickbase.com/db/yourAppID?a=dbpage&pageID=YourJSPageID"></script> 
    </html>​

    JavaScript Page:
    let urlParams = new URLSearchParams(window.location.search);
    let lowRec = prompt("Enter the low Record ID#");
    let highRec = prompt("Enter the high Record ID#");
    let countLength = 0;
    let dbid = urlParams.get("myDbid");
    let myForm = urlParams.get('myFormId');
    let usertoken = urlParams.get('usertoken');
    let apptoken = urlParams.get('apptoken');  
    let root = location.protocol + '//' + location.host;
    const myHostName = "EnterHostName.quickbase.com";
    
    const myDiv = document.getElementById('dbPagePayload');
    var headers = {
      	'QB-Realm-Hostname': myHostName,
    	'User-Agent': 'Find_Records',
    	'Authorization': `QB-USER-TOKEN ${usertoken}`,
        'Content-Type': 'application/json'
    }
    var body = {"from": dbid,"select":[3],"where":`{3.GTE.'${lowRec}'}AND{3.LTE.'${highRec}'}`}
    
    fetch('https://api.quickbase.com/v1/records/query',
      {
        method: 'POST',
        headers: headers,
        body: JSON.stringify(body)
      })
    .then(async res => {
      if (res.ok) {
        return res.json().then(res => {
            console.log(res)
            countLength = res.metadata["numRecords"];
            if (countLength > 1) {
                myDiv.innerHTML += `Found ${countLength} records within the entered range.<br><br>`
            }else if (countLength == 1) {
                myDiv.innerHTML += `Found ${countLength} record within the entered range.<br><br>`
            }else {
                myDiv.innerHTML += `Found 0 records within the entered range.<br><br>`
            };
            console.log(countLength)
            myData(res.data)
        });
      }
      return res.json().then(resBody => Promise.reject({status: res.status, ...resBody}));
    })
    .catch(err => console.log(err))
    
    const myData = (resOriginal) => {
        var counter = 0
        resOriginal.forEach(ele => {
            let val = ele[3].value;
            console.log(`Done - Rec ID Level: ${val}`)
            let myURL = `${root}/db/${dbid}?a=API_GetRecordAsHTML&rid=${val}&dfid=${myForm}&apptoken=${apptoken}`;
            $.post(myURL, {}, function (response) {
                let myDoc = response;
                var opt = {
                    margin: 1,
                    filename: 'myfile.pdf',
                    image: { type: 'jpeg', quality: 0.98 },
                    html2canvas: { scale: 2 },
                    jsPDF: { unit: 'in', format: 'letter', orientation: 'portrait' }
                };
    
                html2pdf().from(myDoc).set(opt).outputPdf('dataurlstring').then(async res => {
                    var base64result = res.split(',')[1];
                    console.log(val);
                            
                    var headers = {
                        'QB-Realm-Hostname': myHostName,
                        'User-Agent': 'File_Upload',
                        'Authorization': `QB-USER-TOKEN ${usertoken}`,
                        'Content-Type': 'application/json'
                    }
                    body = { "to": dbid, "data": [{"3": {"value": val}, "59": { "value": { "fileName": "FormPDF.pdf", "data": base64result }}  }], "fieldsToReturn": [ 3, 59 ] }
    
                    fetch('https://api.quickbase.com/v1/records',
                        {
                        method: 'POST',
                        headers: headers,
                        body: JSON.stringify(body)
                        })
                    .then(async res => {
                        if (res.ok) {
                            return res.json().then(res => {
                                console.log(res)
                                counter++
                                myDiv.innerHTML += `Record ID#: ${val} - Complete - ${counter}/${countLength}<br><br>`
                            });
                        }
                        return res.json().then(resBody => Promise.reject({status: res.status, ...resBody}));
                    }).catch(err => console.log(err))
                });
            });
        console.log(`Done - getURL Record: ${val}`)
        })
    };
    
    
    ​




    ------------------------------
    Sean Connaughton
    ------------------------------



  • 6.  RE: Automatically save a form page as PDF and insert into attachment field?

    Posted 05-27-2022 18:23
    Sean,

    This is very cool.  I was able to get it working and this will definitely come in handy!

    ------------------------------
    Jeff Peterson
    ------------------------------



  • 7.  RE: Automatically save a form page as PDF and insert into attachment field?

    Posted 12-01-2022 10:16
    Hi Sean,

    You were able to get this working and have a PDF attached to a file attachment field? I followed the steps above and all I am getting it to do is open the form as a popup but nothing is saved as a PDF in my attachment field.
    Thanks,
    Niraj

    ------------------------------
    Niraj Shah
    ------------------------------



  • 8.  RE: Automatically save a form page as PDF and insert into attachment field?

    Posted 06-02-2022 18:39
    Edited by Jeff Peterson 06-03-2022 13:31

    I have this working but I can't get it to load any embedded reports on the form to be saved.  Any idea why it won't load them?   

    They are there if you access the link manually, but when it's done via the script it only loads the fields in that table.


    Edit:  It's not the setting for 'When there are embedded reports on the form' in form properties.     Seems to be related to the JS.

    ------------------------------
    Jeff Peterson
    ------------------------------



  • 9.  RE: Automatically save a form page as PDF and insert into attachment field?

    Posted 02-27-2023 08:10

    Very Cool stuff!  Thanks for sharing.  Has anyone here thought how we accomplish this with pipelines?  I'd be interested if someone solved this in that way or any thoughts on how it could be accomplished (if at all).  Thoughts?



    ------------------------------
    Greg
    ------------------------------