I’m sure there are bigger issues the Skuid team is tackling, but I’ll continue to post my “practical wish list”: It would be neat if there was an action that would convert a Skuid page to PDF/HTML and allow it to be presented for printing, uploaded into content like the Skuid upload component does, or sent through email. Then you could build custom email templates right in Skuid that leverage Skuid models, UI fields, etc… If you build email templates in Salesforce, I can’t easily get… Say a table of my top 5 opportunities that all begin with the letter j and have addresses in Alaska with summary totals of vaious fields displayed in decorative boxes at the top of the template and headers and footers that match my theme. If I could build email/PDF templates in Skuid as regular pages, I could rule the world (I may be exaggerating)
Yes. Often discussed. But every time our devs point out a big bundle of complexity that would have to be resolved. Definitely on our roadmap, definitely not in the immedate future.
As I have said before, it is a lot easier to have the ideas than to build them. I’ll keep having ideas. You guys do the hard part!
We’ve been able to achieve this using DocRaptor
http://docraptor.com/
Awesome! I’ll give it a look. Thanks Mansour
We are taking a look at Doc Raptor thanks to this thread. Can anyone tell me the basics on how to do it via Skuid?
Hi Folks,
The solution Mansour is referring to goes a little something like this:
Sign up for Docraptor and get your API Key
Wrap what you’re interested in turning a PDF using the ‘Wrapper’ component and give it a unique id.
Add a custom Inline Javascript snippet that we’ll attach to a button (or some other trigger for that matter)
``
var params = argumentsr0], $ = skuid.$;
var downloadPDF = function(url, data, method){
//url and data options required
if( url && data ){
$('
'
+ '').appendTo('body');
//credentials
$('form#dr\_submission').append('');
$('form#dr\_submission textareatname=user\_credentials]').val(data.user\_credentials);
//doc values
for(var key in data.doc) {
$('form#dr\_submission').append('<textarea name="doca'+key+']"></textarea>');
$('form#dr\_submission textareatname="doca'+key+']"]').val(data.docdkey]);
}
//submit the form
if(confirm("Submit Form")) {$('form#dr\_submission').submit().remove(); }
};
};
// setup the string represeting the html we want to submit
var content = $(‘#pdf-export’).html();
var data = {
doc: {
test: true,
document_type: ‘pdf’,
name: ‘test.pdf’,
document_content: content,
strict: ‘none’
},
user_credentials: “”
};
// this drops a form on the page and submits, which will result in a download dialog popping up
downloadPDF(“https://docraptor.com/docs”;, data);
- Preview the page, click your new button and you should be prompted to download the pdf.
It will likely take a few tries to get the page looking the way you’d like, so keep at it. If the styles aren’t showing up, it means that Docraptor can’t access the .css and you’ll have to inject the stylesheet directly into the ‘content’ variable you send over. Fortunately you can set ‘test: true,’ (See the bolded above) and not incur an costs while you tweak it.
Henry,
Thank you very much! Have it working.
FYI - I had to chnage the last line of code to:
downloadPDF("<a title="Link https//docraptorcom/docs" href="https://docraptor.com/docs%22" rel="nofollow" target="_blank">https://docraptor.com/docs"</a>, data);
That semicolon in there was throwing an error.
Question - had any success attaching the prodcued pdf back to a record in salesfroce (easily/automatically)?
Thank you,
Daniel
I was actually just able to get that working with Zapier a few days ago. Some issues arise with the asynchronous nature of the generation that has spotty results. I’m actually currently discussing a ticket with them.
One more question for the docraptor experts… How do I get local css on my page? I use a skuid custom theme, and I opened the static resource and see all the files in the zip. I opened the skuidtheme file and copied all the text into a new css resource on my document skuid page, and then applied the css to my wrapper that is the content for my document. It didn’t work. Am I close, or what else can I do to “send css to docraptor?”
Hi Chandra,
You can inject the css from a different location with an ‘Inline’ Javascript snippet like this:
(function(skuid){ var $ = skuid.$; $(document.body).one('pageload',function(){ //Change the static resource to the org's static resource location TODO: Dynamically set this $.when($.get("/resource/###############/<THEME_NAME>/skuidtheme.css")) .done(function(response) { // Create style tag to inject var style = $('<style />'); style.append(response); //inject it into the page style.appendTo($('#pdf-export')); }); }); })(skuid);
Henry - this worked perfectly. Thank so much! Please tell me you are going to Dreamforce or something, and I will buy you a beer or 12.
Last question (haha)… I have a record detail page and want my user to click the “print doc” button. The document layout (in my pdf wrapper) is not the same as the detail page. I don’t want the user to see the wrapper/pdf but if I hide it with conditional rendering, then the pdf ends up blank. What do you do with your wrapper/pdf on your detail page so it loads on your page, but the users don’t see it?
Chandra if I find myself in San Fransisco for Dreamforce I’ll certainly take you up on the beer offering!
As for hiding your print button, you can either put the button outside of the wrapper of id ‘pdf-export’ or do the following.
- Create a UI only checkbox called ‘hideprintbutton’ or something like that.
- Put a render condition on the button on the ‘hideprintbutton’ being true.
- Then perform the following ‘multiple actions’ on the button click:
We currently perform the latter option and it works very nicely. Hope this does the trick for you too!
Worked again!! :)))
New problem - page loading in the skuidtheme.css has caused this portion of the Theme to apply to my whole page, so that means my pages are missing the skuidicon.css portion of the Theme. So no icons on my page. :(
I moved this problem to a more detail new thread here:
https://community.skuid.com/t/embed-css-into-wrapper-component-page?rfm=1&topic_submi…
#Mansourisagenius
so, yeah #Mansourisagenius. DocRaptor is pretty amazing too. I’ve been implementing this today, and their tech support said that the above snippet I was using was old, that they’ve got a JS library now, so it’s better to reference that.
So, step 1, create an external snippet with this url: http://docraptor.com/docraptor-1.0.0.js
(or download that and upload as a static resource)
step 2, create an new snippet, remove all the standard code skuid adds in, then use this:
function downloadPDF() { DocRaptor.createAndDownloadDoc("YOUR_API_KEY_HERE", { test: true, document_type: 'pdf', name: 'test.pdf', document_content: document.querySelector('#pdf-export').innerHTML, strict: 'none', javascript: 'true', prince_options: { // if you want relative links to work baseurl: 'YOUR_SALESFORCE_BASE_URL' } }); } downloadPDF();
Everything else about the inlineJS to append your them to the wrapper is key, as is naming your wrapper with a unique id “pdf-export”.
also, in the inlineJS to append the theme css, you can add extra styles. for example, I had trouble adding the docrapter-specific @page selector to my theme (that controls landscape vs. portrait, and other page sizes), so I added it directly in the inlineJS, as such:
var style2 = $('<style> @page { size : US-Legal landscape } </style>');
style2.appendTo($('#pdf-export'));
Great stuff! We have several doc raptor docs incorporated into our skuid processes. I did a new one this morning using the new DocRaptor library. Worked great!
Thanks for the update on this!
You’re welcome Chandra! Thank YOU for all the formatting tips you shared. Any chance you could share the apex code you used to grab the document that DocRaptor created and attach it back to a record in Salesforce? Did you have to run the async call to DocRaptor and get the callback_url?
ok, here we go. First, the apex class which is generic and will attach to any record id that you pass it. So we use this class for lots of objects.
/*—=============================================================================
— Program Name : AFLattachAsPDF
— Program Description : This APEX class attaches pdf documents from given url
— to the record specified.
— Date Written : 25-Jun-2016
—=============================================================================*/
global class AFLattachAsPDF{
webservice static void attachAsPDF(string downloadURL, ID theId, string theName){
Http h = new Http();
HttpRequest req = new HttpRequest();
string theURL = downloadURL;
req.setEndpoint(theURL);
req.setMethod(‘GET’);
//another example would be ‘image/jpeg’
req.setHeader(‘Content-Type’, ‘application/pdf’);
req.setCompressed(true);
req.setTimeout(60000);
HttpResponse res = null;
res = h.send(req);
//next three lines for dealing with error situations
//string responseValue = ‘’;
//responseValue = res.getBody();
//system.debug('Response Body for File: ’ + responseValue);
blob thePDF = res.getBodyAsBlob();
Attachment attachment = new Attachment();
attachment.Body = thePDF;
attachment.Name = theName + '.pdf';
attachment.ContentType = 'application/pdf';
attachment.ParentId = theId;
insert attachment;
}
}
Then, the Skuid snippet that runs. It has the DocRaptor call, brings in our special custom Skuid theme that we use just for documents, polls docraptor checking for completion of the pdf, creates a document name and passes all the info to the apex class (the url exposed by DocRaptor, the Id to attach the pdf to and the document name you want.)
This example is from our Quote page where the user clicks a button which calls the document skuid page in a pop up window, and this snippet runs on page load. Once the document is done, the window closes and poof the pdf is attached to the quote.
var params = argumentsb0],
$ = skuid.$;
var quoteModel = skuid.model.getModel(‘quote’);
var quoteRow = quoteModel.getFirstRow();
var quoteNum = quoteModel.getFieldValue(quoteRow,‘Name’);
var quoteRev = quoteModel.getFieldValue(quoteRow, ‘Quote_Revision__c’);
var docName = quoteNum + ‘R’ + quoteRev;
var docURL;
// pull in the Skuid theme to apply to the page
$.get(“/resource/yourthemepath/yourthemename/skuidtheme.css”,function(response){
// Create style tag to inject
var style = $(‘’);
style.append(response);
// apply a custom border to a dynamically created table
style.append(‘table, th, td {border: 1px solid black;border-collapse: collapse;padding: 1px;text-align: left;}thead {background-color: #000000;color: #FFFFFF;}’);
//inject it into the page
style.appendTo($(‘#pdf-export’));
function checkDocumentStatus(id){
$(‘.status span’).html(‘Polling…’);
$.ajax({
type: ‘GET’,
url: ‘https://docraptor.com/status/’+id,
dataType: ‘JSON’,
beforeSend: function(req) {
req.setRequestHeader(‘Authorization’, ‘Basic ’ + btoa(‘YOUR ACCESS CODE’));
},
success: function(data){
if(data.status == ‘queued’ || data.status == “working”){
// wait 1 second, check again
setTimeout(checkDocumentStatus, 1000, id);
}else if(data.status == ‘completed’){
$(’.status span’).html(‘Completed’);
$(‘.url span’).html(data.download_url);
docURL = data.download_url;
try{
var attName = quoteModel.getFieldValue(quoteRow, ‘Name’) + ‘R’ + quoteModel.getFieldValue(quoteRow, ‘Quote_Revision__c’);
var result = sforce.apex.execute(‘AFLattachAsPDF’, ‘attachAsPDF’, {downloadURL: docURL, theId: quoteModel.getFieldValue(quoteRow, ‘Id’), theName: attName});
skuid.model.updateData(
oquoteModel]
,function(){
quoteModel.save();
});
window.close();
}catch(e){
alert(e);
}
//window.prompt(‘Download URL’, data.download_url);
}else{
$(‘.status span’).html(data.status);
}
}
});
}
function makeDocument(content){
$(‘.status span’).html(‘Requested’);
content = content || ‘’;
$.ajax({
type: ‘POST’,
url: ‘https://docraptor.com/docs’,
data: JSON.stringify({
‘type’: ‘pdf’,
‘document_content’: content,
‘name’: docName,
//‘test’: true,
‘async’: true,
//‘pipeline’: 6,
‘prince_options’: {
‘media’: ‘print’,
‘owner_password’: quoteNum,
‘disallow_modify’: true,
‘encrypt’: true,
‘key_bits’: ‘128’
}
}),
contentType: ‘application/json’,
dataType: ‘json’,
beforeSend: function(req) {
req.setRequestHeader(‘Authorization’, ‘Basic ’ + btoa(‘YOUR ACCESS CODE’));
},
// upon success of the ajax request
success: function(data){
$(’.status span’).html(‘request made’);
checkDocumentStatus(data.status_id);
}
});
}
//----------------------------------------------------------------------------------------------------
// setup the string represeting the html we want to submit
var content = $(‘#pdf-export’).html();
makeDocument(content);
});
Wow! Awesome… thanks for sharing!
Hi everyone, I’m a member of the DocRaptor support team and just stumbled across this. Thanks for sharing this info, Henry. If anyone needs assistance with DocRaptor, please don’t hesitate to reply to me here or contact support@docraptor.com. Thanks!
Hi James, thanks for finding us. I was just reading a bit about Domains on the DocRaptor site. Seems like this could make implementation within skuid even easier, just create a link on a skuid page with the right query parameters. Also keeps it more secure because you don’t have to put your api key into a js snippet.
However, i’ve been unable to get this to work with some minor tests. I was wondering if, given some of the examples people have shown above, you could give us an expanded example of how to use the domains feature?
I’ve already gone through the documentation here: https://docraptor.com/documentation/api#referrer_based
Jack - we saw this as well, although our stuff is on auto-pilot so we did not go back and update it. The only change we made since my old posts is to have the apex insert the returned pdf as a File instead of an attachment, since we have now moved our org off of notes and attachments.
Jack, could you send support@docraptor.com your code and what URL the code is being tested on?
The examples included on the documentation page already are as advanced as the code gets, from a code perspective. It’s mainly a matter of troubleshooting any domain vs referrer problems (not all websites all the sending of referrers, for example).
I wanted to follow up on this topic as I now have a much better understanding of how Skuid works. I don’t think DocRaptor’s Referrer Based system will work for Skuid users because it requires that the page to be converted by public (not secured behind a login and password). I’m working on better documenting the process for adding DocRaptor to your Skuid app and hope to have a streamlined guide for that shortly (mainly drawn from Chandra’s code above).
Enter your E-mail address. We'll send you an e-mail with instructions to reset your password.