dynamic PDF v/s HTML to PDF - javascript

I am currently working on multiple dashboards for the healthcare industry and one of the common requirement is generating PDF from the screen as is. We dont have any common CRUD operations on these dashboards. They typically include a lot of charts (using highcharts), some tabular data, accordions etc. And everything is rendered as a part of few select statements which will be fired on the page load or if a user clicks on some chart or any HTML element.
I am looking into ways to do this and there are 2 options, out of which the most wel-known option is to use third party libraries to generate PDF from the HTML itself which consists of the minimal effort of writing about 3-4 lines of code.
The other option is to write code to dynamically generate PDF which looks like the UI. This will require much more effort since we have to take into consideration the branding and styling, generate charts that look exactly like on the dasboard UI, create tabular data just like on the UI of the dashboard.
The common UI requirement of all the dashboards is to support all major browsers - IE starting from 9, forefox, Chrome, Safari. Also support iPads, last 3-4 versions of iPhones and other most common devices.
The technologies that we use for these dashboards are angular 2.0, some JQuery, HTML, CSS and asp.net web api and in some cases asp.net MVC.
I need to know the pros and cons of above two ways to generate PDF for all these dashboards. I googled about this found very little. Can somebody share some insight into this and give some inputs based on their experience?

Based on what you describe, you'll want to do at least a mix of the two. It's always better if you can use an HTML-to-PDF converter because that saves a lot of development time. But since the UI has things like accordions and such, this means you need to determine how to present that dynamic information in a static PDF.
So the hybrid approach I've used in the past is to use Angular to markup the HTML like this:
<my-accordion ng-if="!ExportingPDF"> ... accordion view for browser ...</my-accordion>
<div ng-if="ExportingPDF"> ... expanded and slightly-modified view for PDF ... </div>
When the user clicks on an "Export PDF" button, you can create a function that will do a $scope.ExportingPDF = true and then grabs all the visible HTML on the page (after a short $timeout delay to give Angular time to update the DOM).
Then your ExportPDF function will POST the HTML to the server where a server-based HTML-to-PDF code library will convert the HTML and then send it back to the browser as a file download attachment.
Example code:
$scope.ExportPDF = function() {
$scope.ExportingPDF = true;
$timeout(function() {
$ajax.post("/path/to/conversion-routine.abc", { data: $('html')[0].outerHTML }
}, 50); // short delay so Angular has time to update the DOM
}
This lets you utilize the power of Angular and your existing markup while still dealing with all the weird little UI things that need to be adjusted to present properly in a static PDF document.

Related

Android WebView does not display Images from an HTML String

I'm trying to load a "webpage" using the Android WebView but the images won't load. Firstly, I retrieve a text String that's formatted in Markdown. Afterwards, I convert the Markdown into HTML using Markdown4J, and then using the Android WebView's loadDataWithBaseUrl() function, I load the WebView with the html.
String html = null;
try {
html = new Markdown4jProcessor().process(mText);
} catch (IOException e) {
e.printStackTrace();
}
String css = "<link rel=\"stylesheet\" type=\"text/css\" href=\"blogstyle.css\" />";
final String htmlData = css + html;
body.loadDataWithBaseURL("file:///android_asset/", htmlData, "text/html", "UTF-8", null);
Everything in the webview displays and is formatted properly except the images. The images just won't show, and there are definitely image tags inside of the HTML, such as
<img src="https://www.random.org/analysis/randbitmap-rdo.png">
And I have no idea why my WebView wouldn't be able to display this image?
EDIT: The internet permissions in the manifest is already requested. And here is an example of a sample markdown string. I then convert this line into HTML.
"One of the huge problems today with web development is that it isn’t modular; because of how CSS and HTML work, it’s extremely difficult to just drag and drop an element from one site into another without some very strange side-effects. Shape and size can be different, resources can fail to load based on relative paths, and you have to import at least a .html, .css and .js file for each element. Even with all that, there’s no guarantee you won’t have CSS or JavaScript collisions.\n\n \n\nThe solution to this problem? [**Web Components**](http://webcomponents.org/). Now you should know up front that Web Components don’t work in IE and Safari, but they *are* under development.\n\n \n\nSo, what are web components? Well, essentially, they are plug-n-play modules for the web. The picture here is actually a great example. If you’re familiar with web design, imagine how long this would take to make, even statically. You’d have to position the images, set the roundness, give a height to the three main elements, set the font colors… Basically, it’d take you more than five minutes to get this up-and-running.\n\n![blog-image](https://www.ruralsourcing.com/wp-content/uploads/2014/09/blog-image-265x300.png)\n\nSo what if I told you *all the code for what you see is two lines?* Just these two:\n\n \n\n\n <linkref=\"import\"href=\"gitcard.html\">\n <github-carduser=\"nasawa\">\n\n\nAnd that’s all. Just import the html and use the custom element! Using a new templating system called *Shadow DOM*, the browser holds a template called *github-card* with encapsulated styles and JavaScript. This way, even if you have elements named the same, there will never be any collision. And of course, you can have the *github-card* tag wherever you want, as many times as you want, and data will not transfer over.\n\n \n\nOn the other end, if you’re creating a web component, you can easily add as many customizable fields as you want to allow the user to modify your component at specific spots. For example, this is what the simplified Google Maps component looks like:\n\n \n\n\n`<google-mapslatitude=\"30.686603\"longitude=\"-88.046224\"></google-maps>`\n \n\nAnd a complicated Google Maps component looks like this:\n\n\n <google-maplatitude=\"37.77493\"longitude=\"-122.41942\"fitToMarkers>\n <google-map-markerlatitude=\"37.779\"longitude=\"-122.3892\"\n draggable=\"true\"title=\"Go Giants!\"></google-map-marker>\n <google-map-markerlatitude=\"37.777\"longitude=\"-122.38911\"></google-map-marker>\n </google-map>\n\n\n \n\nAs you can see, it is truly a great time to be in web development. Complex procedures are getting better and easier every day as we push closer to a true implementation of HTML5 and a unified multiplatform experience, and web components are a spearhead on that advancement. Look out for the next big thing – it’ll be here before you know it!\n\n \n\nChristopher Johnson \n Jr. Associate Programmer"
which would give me the following in HTML:
<p>"One of the huge problems today with web development is that it isn’t modular; because of how CSS and HTML work, it’s extremely difficult to just drag and drop an element from one site into another without some very strange side-effects. Shape and size can be different, resources can fail to load based on relative paths, and you have to import at least a .html, .css and .js file for each element. Even with all that, there’s no guarantee you won’t have CSS or JavaScript collisions.</p>
<p> </p>
<p>The solution to this problem? <strong>Web Components</strong>. Now you should know up front that Web Components don’t work in IE and Safari, but they <em>are</em> under development.</p>
<p> </p>
<p>So, what are web components? Well, essentially, they are plug-n-play modules for the web. The picture here is actually a great example. If you’re familiar with web design, imagine how long this would take to make, even statically. You’d have to position the images, set the roundness, give a height to the three main elements, set the font colors… Basically, it’d take you more than five minutes to get this up-and-running.</p>
<p><img src="https://www.ruralsourcing.com/wp-content/uploads/2014/09/blog-image-265x300.png" alt="blog-image" title="" /></p>
<p>So what if I told you <em>all the code for what you see is two lines?</em> Just these two:</p>
<p> </p>
<pre><code><linkref=\"import\"href=\"gitcard.html\">
<github-carduser=\"nasawa\">
</code></pre>
<p>And that’s all. Just import the html and use the custom element! Using a new templating system called <em>Shadow DOM</em>, the browser holds a template called <em>github-card</em> with encapsulated styles and JavaScript. This way, even if you have elements named the same, there will never be any collision. And of course, you can have the <em>github-card</em> tag wherever you want, as many times as you want, and data will not transfer over.</p>
<p> </p>
<p>On the other end, if you’re creating a web component, you can easily add as many customizable fields as you want to allow the user to modify your component at specific spots. For example, this is what the simplified Google Maps component looks like:</p>
<p> </p>
<p><code><google-mapslatitude=\"30.686603\"longitude=\"-88.046224\"></google-maps></code>
 </p>
<p>And a complicated Google Maps component looks like this:</p>
<pre><code><google-maplatitude=\"37.77493\"longitude=\"-122.41942\"fitToMarkers>
<google-map-markerlatitude=\"37.779\"longitude=\"-122.3892\"
draggable=\"true\"title=\"Go Giants!\"></google-map-marker>
<google-map-markerlatitude=\"37.777\"longitude=\"-122.38911\"></google-map-marker>
</google-map>
</code></pre>
<p> </p>
<p>As you can see, it is truly a great time to be in web development. Complex procedures are getting better and easier every day as we push closer to a true implementation of HTML5 and a unified multiplatform experience, and web components are a spearhead on that advancement. Look out for the next big thing – it’ll be here before you know it!</p>
<p> </p>
<p>Christopher Johnson <br />
Jr. Associate Programmer"</p>

Effeciency, hidden HTML or JavaScript DOM appending?

I am working on a simple Cordova app with about 4 page types and I am trying to think through which is the better way to handle the inner HTML templates.
Hidden HTML hard coded into the HTML files that is hidden and populated/revealed by my JS.
Using a JS template system and appending and removing from the DOM.
I feel that appending all that to the DOM for a page is inefficient when I could just update the sections that change. But perhaps an append is lightweight enough where I shouldn't worry about it.
There are a number of ways you can do it. In terms of load on the browser. That is hard to say. From your question it is hard to know what is in these pages, what are you displaying, is it live data, static html etc.
When you first plot out an app, if you are from the old class of building multiple page websites, it can be a little concerning as to how well your app/page will run with all those pages crammed in to one, and all that data plus code.
The answer is, amazingly well. If done properly in modern browsers, and for example Ipads the app will run to near native performance.
The options you have are
Map all the pages into one HTML document. Hide each page content using css display:none, flip them into view using css animation, fading or just display:block.
Use a javascript routing library to map urls to blocks of code that deal with each page, this makes mapping out your app much easier, and means that buttons can just link to your pages, like a real website. see http://projects.jga.me/routie/
Building all the page templates into one page can make it hard to code, as the page becomes enormous, consider breaking the inner content of each page into separate files, you can then give each page holder a url and use a small xhr request to load the page on-the fly, once loaded you can cache it into memory or even local-storage, depending on whether you remove it when it is closed or keep it hidden.
In my experience you can put an enormous number or nodes into one page and have very little speed drop, bear in mind if you use something like jquery and do a lot of $(".page > .page1 > .items li") your going to have a slow app.
Tips
Use element ID's everywhere document.getElementById(..) is 100's of times faster in a loop that $(...)
cache elements when you find them, if you need them later store them in a memory cache.
keep for loop inner code to a minimum.
use a decent click touch libary like http://hammerjs.github.io/ and delegate all the events of the body tag or at least on each page.
If you need to touch the server, load data, think dom first, device second server later. A good app is a responsive app, that responds to the user instantly.
I know this has been posted a while ago, but for the sake of the users I am going to add my answer.
I completely agree with MartinWebb but my answer will shed some light on the results of his options. I am currently working on a similar project. Please note that this answer pertains to cordova (previously called phonegap) specifically. My app has about 5 pages with +-20 different components (input's, div's, h1's, p's, etc.). This is what i tried and the result of each:
jQuery was my first option, mainly because it is easy to use and reduces the amount of code required to accomplish a said goal. Result: First time I tried this approach I though I would spice it up with animations and transformations. The result of this was a very unresponsive app. I removed the animation and transformation, however due to the nature of my application I required multiple dynamically added components and jQuery just wasn't up for the task.
Css display:none and visible:hidden was my next option. I used javascript's dom to display certain div's. Result: This works if your not planning on switching many div shortly after one another eg. a simple menu. It quickly became apparent that this wasn't going to work. Also this does not eliminate my need for the dom. Remember document.getElementById('menu').style.display = "none"; is still part of the dom. This as a solution, for me, is poor. There is a reason that var menu= document.createElement('div'); is part of the language. Which brings me to my last option.
Building a page 90% on javascript's dom was my last option. Logically I could not see how 600 lines of code cold trump one .innerHTML or .style.display = "block"; but it did. Result: It was by far the most responsive of all the solutions.
I'm not saying that all webpages should be coded with dom appending, but as I stated previously, for a cordova app of a few pages (<6), with a few components a javascript dom appending approach would be best. It takes longer to code, but you will be rewarded with control and efficiency. I would suggest coding the backbone of your app in html and populating and controlling with javascript's dom.
Best of luck.
The first option, <div>s with display:none; would be more efficient by a small margin, but you can get the best of both worlds by compiling your JavaScript and templates together into a single file using something like browserify or require.js.

Raw AngularJs markup appearing in Google search results page

We just updated portions of our website with AngularJS - particularly the login page. When I look at the search results in Google, the cached page and the small snippet it displays automatically is the raw Angular markup. So, lots of {{model.username}}, {{model.errorMessage}}, etc.
I won't link the results since it's too embarrassing.
Any idea of how do get Google to actually store the page as rendered vs. the raw HTML?
It would be wonderful if you would convert your embarrassment into a community service for all of us by testing something, since you are seeing a condition few people admit to or want to reproduce themselves. :)
Google is known to be relatively (or very, depending on who you ask) good at ignoring hidden content. They implemented this way back when people used to keyword-stuff content by using blocks that were either set to "display: none" or had a tiny/unreadable/white-on-white font.
What you're seeing is a problem for more than just SEO, so I'm suggesting this because things like prerender.io are great but they only solve that one piece. What about users who simply have slow browsers? Well, it turns out Angular has a great solution for this called ngCloak. It hides things like template content fields (ngModel mappings and bindings, expressions, etc) until Angular is ready to fill them in itself.
It's very easy to implement this; you just need a small block of CSS (in an early-loaded file, or embedded directly into your HTML page):
[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
display: none !important;
}
and then you apply the ngCloak directive to items that are affected, or to a high-level parent (like your ng-view DIV):
<div id="wrapper" ng-cloak>
<!-- Page content here -->
</div>
This works kind of like a no-js target, but specifically for AngularJS.
You'll still want something specific to give Google that is actually good material, but at least with the above you can filter out everything else.
SEO for angular is a really big question/issue depending on your perspective. I would start by reading http://www.ng-newsletter.com/posts/serious-angular-seo.html and http://www.yearofmoo.com/2012/11/angularjs-and-seo.html to get you started.
To sum up your primary options:
change your routing system to use the hashbang (#!). Then sites like google and facebook will convert the hashbang to _escaped_fragment_ before querying your page. This gives your server an opportunity to return different html.
use a service like http://prerender.io which will pre render and cache rendered versions of your site for you, which will be provided to google in place of your site.
There are still issues with things like sharing to reddit and stumbleupon for example, as they are lazy and don't want to develop to cater to angular based sites. So for certain circumstances you will have to get creative.
Update: One thing we have done on a recent project is look at the various user agents to determine if crawling systems are asking for page information. This way we can serve what ever we like.

Highlight spots in PDF documents that are embeded in HTML

Employees need to check data imported using OCR. They have web interface showing imported data on the left side and the scanned image on the right. When dealing with a large list of items they get lost and are asking for a tool/pen able to highlight (PDF) rows that are already checked.
Is there any chance to use JavaScript and draw to the PDF that is viewed?
If you are viewing the PDF in a plug-in, the answer is no, not through JS.
If, however, you can leverage a tool like pdf.js, this may be possible, depending on what your document uses in terms of PDF elements. For example, pdf.js has an Annotation plug-in, which looks like it may enable you to actually create annotations.
You will not be able to save the changes, however. If you want to do this, you are strongly encouraged to use a proper UI and not just a PDF (though, you may read from the PDF to generate it).

Designing a website for both javascript script support and not support

Okay i know that it's important for your website to work fine with javascript disabled.
In my opinion one way to start thinking about how to design such websites is to detect javascript at the homepage and if it's not enabled redirect to another version of website that does not javascript code and works with pure html (like gmail)
Another method that i have in mind is that for example think of a X (close button) on a dialog box on a webpage. What if pressing the X without any javascript interference lead to sending a request to the server and in the server side we hide that dialog next time we are rendering the page, And also we bind a javascript function to onclick of the link and in case of the javascript enabled it will hide the dialog instantly.
What do you think of this? How would you design a website to support both?
One way to deal with this is to :
First, create the site, without any javascript
Then, when every works, add javascript enhancements where suitable
This way, if JS is disabled, the "first" version of the site still works.
You can do exactly the same with CSS, naturally -- there is even one "CSS Naked Day" each day, showing what websites look like without CSS ^^
One example ?
You have a standard HTML form, that POSTs data to your server when submitted, and the re-creation of the page by the server displays a message like "thanks for subscriving"
You then add some JS + Ajax stuff : instead of reloading the whole page while submitting the form, you do an Ajax request, that only send the data ; and, in return, it displays "thanks for subscribing" without reloading the page
In this case, if javascript is disabled, the first "standard" way of doing things still works.
This is (part of) what is called Progressive enhancement
The usual method is what's called progressive enhancement.
Basically you take a simple HTML website, with regular forms.
The next enhancement is CSS - you make it look good.
Then you can enhance it further with Javascript - you can add or remove elements, add effects and so on.
The basic HTML is always there for old browsers (or those with script blockers, for example).
For example a form to post a comment might look like this:
<form action="post-comment.php" method="post" id="myForm">
<input type="text" name="comment">
</form>
Then you can enhance it with javascript to make it AJAXy
$('#myForm').submit(...);
Ideally the AJAX callback should use the same code as post-comment.php - either by calling the same file or via include, then you don't have to duplicate code.
In terms, it is not important to make your site work with JavaScript disabled. People who disable JavaScript are people who want to hack bugs into your site, they don't deserve to navigate it correctly. Don't waste your efforts with them. Everybody know the Web is unsurfable without JavaScript.
The only thing you have to be careful is about your forms: Don't ever trust filters in JavaScript, Always filter it again on server-side, ALWAYS!
Use Progressive Enhancement, study jquery to understand it. It takes some time till you get your head around it. For example your idea:
to detect javascript at the homepage
and if it's not enabled redirect to
another version of website that does
not javascript code and works with
pure html
how would you detect if javascript is disabled? not with javascript, obivously...
you're thinking the wrong way round: the most basic version has to be the default version, and then, if you detect more advanced capabilities, you can use them.
Try to avoid separate versions for different bowsers/capabilities for as long as you can. It's so much work to keep all versions in sync and up-do-date.
Some good ressources to get you started:
Understanding Progressive Enhancement
Progressive Enhancement with JavaScript
Test-Driven Progressive Enhancement
The best way is to design a page that works adequately without JS. Then add a <script> block at the bottom of the <body> section with code like this:
window.onload = function() {
// Do DOM manipulations to add JS functionality here. For instance...
document.getElementById('someInputField').onchange = function() {
// Do stuff here that you can't do in HTML, like on-the-fly validation
}
}
Study the jQuery examples. They show lots of things like this. This is called "unobtrusive JavaScript". Google for that to find more examples.
EDIT: The jQuery version of the above is:
$(document).ready(function() {
// Do DOM manipulations to add JS functionality here. For instance...
$('#someInputField').change(function() {
// Do stuff here that you can't do in HTML, like on-the-fly validation
});
});
I added this just to show the lower verbosity of jQuery vs. standard DOM manipulation. There is a minor difference between window.onload and document.ready, discussed in the jQuery docs and tutorials.
What you're aiming for is progressive enhancement. I'd go about this by first designing the site without the JavaScript and, once it works, start adding your JavaScript events via a library such as jQuery so that the behaviour of the site is completely separate from the presentation. This way you can provide a higher level of functionality and polish for those who have JavaScript enabled in their browsers and those who don't.

Categories

Resources