Project

General

Profile

Frequently asked questions.

1. Is the plugin compatible Servoy 3.5.x? Is it compatible Servoy 4.x?

  • The Velocity Report plugin is using some features only available with the Servoy 5.x public API, so it is not compatible with Servoy 3.5 or Servoy 4.
    There is no plan to support these platforms.
    Servoy 3.5 is not going to be supported anymore by Servoy in a few weeks, and as for Servoy 4.x, I see no reason for not upgrading to Servoy 5.

2. Why another reporting tool for Servoy?

  • If you ever tried to make a report in Jasper Reports with tables containing different columns, and that the number of columns is not really know at design time, or is supposed to change from one page to the next or even inside the same page...
    Or if you have tried to do complex reports with a certain number of pages, each having a different structure, a chart here, a table there, etc., you will easily understand the advantage of using HTML layout capabilities. HTML combined with extended CSS is used for what it is good for: easy and powerful layout of any kind of data.
    That's what the plugin is helping you to do, right inside Servoy!

3. What's the use of Velocity?

  • HTML/CSS is easy to write, but quite verbose, and if you have ever written HTML with Servoy's Javascript methods you certainly ended up with a mixture of HTML and variables concatenated one way or the other...
    It's fine when you do it first, but months later, when you need to add a column in a table for example, this is going to be tough because your code will be hard to read and modify (with escape quotes and + signs all over the place).
    This is where Velocity comes to the rescue: instead of using String concatenation to insert your data, just put a placeholder (a velocity variable, which is a simple name starting with the $ sign) inside your HTML text, then you can use the plugin to easily replace these placholders by the data you provide in a context Javascript Object.
    Nice and clean, and a lot more readable/maintanable in the long run.

4. Should I store the templates on the server or on the client side

  • Server-side, in the folder you have declared with the server 'velocityreport.reportfolder' plugin property.

5. The plugin is not finding my templates, what can I do?

  • The plugin is looking for its templates inside a folder that you have declared in the server admin 'plugins' page, with the 'velocityreport.reportfolder' property.
    If not provided, the plugin will try to find your reports inside your 'user.home' folder (on the server side).

6. Can I use a hierarchy of folders to put my templates inside the reports folder?

  • Of course, you can! Just put the relative path to your templates starting from the report folder - for example if your report is 'template.html" and is located inside a 'testReports' folder in the report folder just use 'testReports/template.html' as the name of the template to render.

7. I have a parse Exception when I use my html page, what is this?

  • Most likely, your HTML is not well formed XHTML.
    The xhtmlrenderer library that we use to parse the templates is only accepting valid XHTML or valid XML.
    Meaning that all tags must be properly closed (even empty tags must be close, ie <br/> or <hr/> for example and even <img src="" />, that all the attributes of tags must be enclosed inside double quotes, that all tags must be lowercase.
    Usually when you have a parse exception, in preview and the resulting PDF you will see a stack trace that should tell you which tag is wrong.

8. What encoding should I use for my templates/macros/css files?

  • The plugin is expecting UTF-8 encoded files. Using other encoding will lead to unexpected character errors.

9. Why do my charts appear all jagged when I print my PDF?

  • Did you install the Eastwood war in /application_server/server/webapps/?
    And did you set the 'useLocalEngine' parameters of your charts to true?
    Otherwise the charts will be using the Google Charts engine which is not capable of rendering high definition images.
    Did you specify REPORT.RESOLUTION_HIGH in the getPDFReport() method or use the savePDFResolution: REPORT.RESOLUTION_HIGH defaultPreview parameter?
    If not, the PDF will be rendered in low (screen) resolution.

10. Why do I have to use plugins.getMedia("image.png"); instead of "media:///image.png"?

  • To be recognized, a media URL need to be interpreted by a URLStreamHandler that is part of Servoy.
    In case of preview in a browser, if you embed an image without using the plugins.getMedia() method, this will be interpreted by the browser, which has no idea of the media protocol and how to resolve the URL, so this will fail to produce the image.

11. Why are the media images embedded in reports not viewable in web preview/pdf when launched from a server?

  • Previewing media URL in a browser from a web client launched in developer works but it doesn't (yet) when launched from a real Servoy server.
    This is because of an issue with Servoy 5.1.x that it supposed to be fixed in Servoy 6.
    I have a feature request in the Servoy support system to ask for a backport of this functionality.

12. What is the "velocityreport.cacheCheckTime" server property for?

  • Velocity can cache templates. And it also allows for a certain expiration time for them, meaning that it will check if templates have changed, but will do this after a certain lifetime of the file in cache.
    This is the value that you can put here that will define if the cache will be used and how many seconds Velocity will wait before checking if there is a new version in the reports directory.
    If you leave it, a value of 0 second is assumed and no cache will be used.
    This is useful in Developer or when you are creating/tweaking your reports. Once in production you can put a value here, this will give a little bit more performance.

13. What's the use of the renderTemplate() and evaluateWithContext() method?

  • These two methods are here to give you access to Velocity even if you are not using it to output PDF, in fact you can use templates to merge templates with context objects and put the result in HTML_AREA fields if you want.
    You can do so using simple String as a template with the evaluateWithContext() method or with a template file located in your reports folder.
    The result will be a String concatenation of your template and all placeholders (Velocity variables) integrated using the context Javascript object that you will have passed as a parameter.

14. What is the meaning of $baseHREF in the sample templates and where does it come from?

  • When you put a $baseHREF variable inside the <head>...</head> tag of your html, it will output a <base href="http://servoyServer/locationOfYourReports" /> in the html head which, when you render the template, will allow the plugin and the browser to find relative resources (css, images).

15. Apart from $baseHREF, are there other objects that I can use in my templates?

  • You can use:
    • $globals to access any global variables,
    • $scopes to access any scopes variables (Servoy 7+),
    • $i18n to access any i18n value that was not already put in the context object and access values either with $i18n.mykey or $i18n.get('mycomplex.key') or $i18n['mycomplex.key'] and retrieve current localeDateFormat and localeNumberFormat,
    • $date to format dates (adapted from the Date generic Velocity tool, one method available: format('yyyy-MM-dd',$dateObject),
    • $math to perform maths (see the Math generic Velocity tool),
    • $number to work with numbers (see the Number Velocity tool),
    • $alternator in your macros (see the Alternator Velocity tool).
    • $plugin to use the humanize(), getTypeCssClass() and wrapTemplate() inline methods, also in #foreach loops on foundsets or dataset, you can use isNumber($field) or $field.isNumber(), isDate($field) or $field.isDate(), isBlob($field) or $field.isBlob() and isString($field) or $field.isString(),
    • $htmlize, using its get() method you will be able to embed html coming from context values, and this html will be properly parsed and included, not escaped as it would be otherwise
    • $valueLists gives you access to value lists, the way the application node does: you can call $valueLists.nameOfValueList.get($keyObject) or $valueLists.getDisplayValue('valueListName',$keyObject) in your template, and you can iterate on a value list using #foreach($item in $valueLists.nameOfValueList) $item.realValue $item.displayValue #end,
    • $null: provide 2 methods: isNull($object) and isNotNull($object),
    • $now: a simple date object, that evaluates to new Date(),
    • $escape: utility to escape various outputs for Java, JavaScript, HTML, XML and SQL (see the Escape Velocity tool)
    • $numberToEnglishWords: utility to convert numbers into english words. Only one method: convert(Number|number as String)

16. Can I use upper case tags - can I mix lower/upper tags in my xhtml?

  • The xhtmlrenderer library used to parse XHTML is very sensitive to xml standards and don't accept mixed lower/upper tags.
    In fact it doesn't accept uppercase either.

17. What are the formating options for my report?

  • The renderer uses CSS 2.1 + @Page CSS 3 extensions to layout your html.
    See the Layout page for more information about it.

18. I have an error in my log about velocity.log when I try to use the plugin, what can I do?

  • Make sure Servoy has read/write permissions on the application_server folder, because the Velocity engine is writing a log called velocity.log inside it (next to the servoy_log.txt)

19. What are the default report parameter?

  • Right now there are 4 values that you can put in the defaultReportParameters, (see the plugin setDefaultReportParameters() addDefaultReportParameter() removeDefaultReportParameter() and clearDefaultReportParameters()):
    • dateFormat (String) defines the default format to use for dates inside all reports
    • numberFormat (String) defines the default format for numbers inside all the reports
    • oneBasedLoops ( true/ false ) allows to set the behavior of foundset.getRecord() and dataset.getRow() to be 1-based (Servoy behavior) or 0-based (default, Java/JavaScript behavior)
    • jsonDateFormat one of JSONDATE constants, see FAQ 34 for an explanation

20. What are the default preview parameter?

  • Using the plugin setDefaultPreviewParameters() addDefaultPreviewParameter() removeDefaultPreviewParameter() and clearDefaultPreviewParameters() you can change the behavior of the smart client preview.
    The available options are:
    • useSaveLocalPDF ( true / false ) - if true, this will show the 'save local PDF' button
    • useTogglePaginated ( true / false ) - if true, this will show the 'toggle paginated' button
    • useZoom ( true / false ) - if true, this will show the zoom buttons
    • useFontZoom ( true / false ) - if true, this will show the font zoom buttons
    • usePrint ( true / false ) - if true, this will show the print button
    • savePDFResolution - Integer (REPORT.RESOLUTION_LOW or REPORT.RESOLUTION_HIGH), the resolution that will be used when a PDF is saved from the preview window
    • saveCallback - if a function is provided, it will be called back when the user click on the save PDF button of the preview, with a byte[] array containing the resulting PDF bytes.
    • printCallback - if a function is provided, it will be called back when the user click on the print button of the preview, with a byte[] array containing the resulting PDF bytes.
    • documentLoadedCallback - if a function is provided, it will be called back when the document is fully loaded in the viewer, with not parameters passed
    • showToolBar ( true / false ) - if true, will show the tool bar
    • showStatus ( true / false ) - if true, will show the status bar
    • bounds Object - can be an array of 4 integer [x, y, width, height] or an Object eg. {x: 10, y: 10, w[idth]: 640, h[eight]: 480} - if not provided, the dialog will be placed centered on the user's screen and with a width/height calculated on what is to be displayed. You can provided only a few parameters, it is equivalent to the -1 value when opening a FID in Servoy
    • openInPaginated (true / false ) - if true, will open in paginated preview mode, false otherwise.
    • horizontalScrollbar or hScrollbar - one of PREVIEW.HSCROLLBAR_ALWAYS, PREVIEW.HSCROLLBAR_ASNEEDED or PREVIEW.HSCROLLBAR_NEVER
    • verticalScrollbar or vScrollbar - one of PREVIEW.VSCROLLBAR_ALWAYS, PREVIEW.VSCROLLBAR_ASNEEDED or PREVIEW.VSCROLLBAR_NEVER
    • border - uses the same syntax as the SolutionModel JSComponent.border, used to set a border for the viewer
    • allowSelection (true / false) - allows selecting text in the viewer, and ctrl+c / ctrl+a

21. Why is such and such option of the google API not implemented in Eastwood?

  • The Eastwood project, if not discontinued, has seen very low activity this last year, it is based on a previous version of the Google Charts API.
    Although the JFreeCharts engine which powers the Eastwood project is very powerful (and very much alive) and could provide for most of the option you have with the Google Charts API, some features are not implemented yet.
    To do so will require a rather big amount of work and some time to grasp the huge JFreeCharts API, which is an ongoing process.
    If you think that some options are really missing and you need them you can try implementing them yourselves or we can discuss about how to do it.
    In the meantime, we think the current implementation is already good enough to be used in production.

22. When I try to create a PDF I have no output, what's happening?

  • In some cases, you can run into what is called 'jar hell', meaning that the expected library is found but the version is not the one that is compatible with the plugin, this will prevent PDF from being produced.
    This can be the case because the plugin is using iText for PDF rendering.
    We have made sure to use the latest iText usable (2.1.7 - further version are not Free software anymore).
    This one is the same version as the latest version used by Jasper Reports so no clash should happen here.
    However, depending on the Servoy 5 version you use, the PDF Output plugin is also using iText but the version used (as of Servoy 5.1.2) is 2.0.3.
    This version is not compatible with xhtmlrenderer (nor the latest Jasper Reports).
    So you will need to extract the pdf_output.jar, pdf_output.jar.jnlp and the pdf_output folder from your plugins folder in order to use the Velocity Report plugin until Servoy updates the iText used here with the latest 2.1.7 version.

23. How can I format my blob images contained in foundsets or datasets (or image byte[] coming from the file plugin)?

  • In your template you can use the "getImageTag()" method on any object coming from foundset or a dataset (or image byte[] coming from the file plugin). If the value is not an image, the value will be rendered, but if the value is a blob (byte[] of the image) then a tag with a rendering URL will be included. To manipulate a few attributes of this tag, you pass a Map to the getImageTag() method, directly into the template, like this:
    $!blobObject.getImageTag( { 'width': 200, 'height': 150, 'class': "blobCssClass", 'id': "blobCssID" } )
    //(you can also use 'w' and 'h' instead of 'width' and 'height')
    // this will render as:
    <img src="theinternalURLOfYourBlobObject" class="blobCssClass" id="blobCssID" width="200" height="150"/>
    

    Note the use of brackets {} to signify an object, and the use of single quotes to define the properties names.
    None of these properties are mandatory, if you don't provide them they will not be integrated in the <img> tag, that's all.
    You can also use the value -1 for width/height to ask the plugin to calculate one of width/height to keep aspect ratio.

24. There are issues with $number.format() in my template

Using $number.format('#,###.00', $anumber) or any other pattern using # or $ might cause troubles in your template
A workaround is to put the format you want to use in the context object, and then use it in the format method.
For example, in Servoy:
context.myFormat = '#,###.00';
In the template:
$number.format($myFormat, $anumber)

25. I want to use $ or # signs in my template but this is causing a CantRenderException, what can I do

In your data (in the context), there is no problem using $ or # signs, but in the template it can cause exceptions due to the fact that Velocity will try to interpret them as variables or directives.
Using a backslash you can escape these special characters, so: \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\$ and \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\# will output correctly as $ and # respectively.

26. My font isn't embedded in the PDF

First make sure that your fonts is in the default report folder location (as set in the admin with the "velocityreport.reportfolder" property) and in a subfolder called /fonts.
Then make sure that you call plugins.VelocityReport.installFonts() or plugins.VelocityReport.installFonts(yourCallbackFunction) before trying to produce PDF from VelocityReport.
This call ensure that the fonts files are pushed to the client's "user.home" in a /.servoy/fonts folder. This is where VelocityReport will look for fonts to embed in your PDF.
NB: for the time being, VelocityReport can only use TTF type fonts file.

27. What if I want to use a HTML String instead of a template file?

You can pass a String containing the HTML you want rendered to the renderTemplate, previewReport, updateComponent, or Viewer.update methods.
Just put a 'fromString: true' property inside your context.

28. Are the $foundset.getRecord() and $dataset.getRow() starting with index 1 like in Servoy?

$foundset.getRecord() and $dataset.getRow() and any loops iteration are zero-based like in Java.
If you find it confusing because it's not the behavior you are used to, you can change that: simply set the defaultReportParameter 'oneBasedLoops' to true.

29. Why do I have scripting errors when I try to use one of the plugin constant?

You first have to touch the plugin, at least once (in your solution onOpen for example), to ask Servoy to load the constants in the scripting environment.
Adding a simple:

plugins.VelocityReport;

will be enough to allow you to use the constants anywhere in your solution after that.

30. How can I prevent VelocityReport from escaping html tags?

You have html in your variables, but they appear as text, when you would like them to be rendered as proper HTML.
Simply use the $htmlize.get() function or better yet the #h() macro to render your html, for example, with a variable in your context like:

context.foo = "<b>bar</b>";

In the template you can use
$htmlize.get($foo)
or
#h($foo)

And the html will be rendered.

31. Can I callback Servoy functions from inside my report to get extra values computed inline?

Sure you can, from v1.5.5 any function that you have added to the context of your report will accept parameters, using a standard JavaScript call.
For example, say you want to add images based on some foundset image names. You can create a function like this:

function getImageFileContent(imgPath) {
       if (imgPath) {
              var file = plugins.file.convertToJSFile(imgPath);
              if (file && file.exists()) {
                     return plugins.file.readFile(file);
              }
       }
       return null;
}

Then add your function to the context like this:

context.func = getImageFileContent;

Then in your template, you can use it like this, for example in a foundset loop:

<table>
#foreach ($record in $foundset)
  <tr>
    <td>$!record.id</td>
    <td>$!func.call($record.imagePath)</td>
  </tr>
#end
</table>

32. How can I use dynamic templates from a String?

You can use a call to $plugin.wrapTemplate() to create a template 'on-the-fly' based on the content of any variable that is in your context.
So for example you will be able to do:

#foreach($record in $foundset)
    #parse($plugin.wrapTemplate($record.myTemplateField))
#end

33. Is the plugin i18n ready?

It sure is! You can customize the tooltips in the viewer and various messages.
All you have to do is to insert your own values for the messages above in your i18n properties and they will be picked up automatically:

Here's the list, with the related default values (the {0} will be replaced by the name of your report, and {1} by the path where the PDF will be saved):

  • velocity.viewer.saveButton=Save to local PDF file...
  • velocity.viewer.printButton=Print the document
  • velocity.viewer.printPreviewButton=Toggle between paginated and continuous view
  • velocity.viewer.zoomButton=Reset zoom to 100%
  • velocity.viewer.zoomInButton=Zoom in
  • velocity.viewer.zoomOutButton=Zoom out
  • velocity.viewer.fontResetButton=Reset font size
  • velocity.viewer.fontIncreaseButton=Increase font size
  • velocity.viewer.fontDecreaseButton=Decrease font size
  • velocity.viewer.savePDFMessage=Saving PDF report "{0}" to {1}...
  • velocity.viewer.printPDFMessage=Printing report "{0}"
  • velocity.viewer.saveDone=Done!
  • velocity.viewer.paginatedView=Paginated view
  • velocity.viewer.overwriteQuestion=Overwrite existing file?
  • velocity.viewer.overwriteDialogTitle=Confirm Overwrite

34. How can I hide scrollbars in the Viewer?

1/ you can set defaultPreviewParameters,

var previewParams : { hScrollbar: PREVIEW.HSCROLLBAR_NEVER, vScrollbar: PREVIEW.VSCROLLBAR_NEVER };
plugins.VelocityReport.setDefaultPreviewParameters(previewParams);

2/ you can update the viewer after it has been initialized:

viewer.setHorizontalScrollbar(PREVIEW.HSCROLLBAR_NEVER);
viewer.setVerticalScrollbar(PREVIEW.VSCROLLBAR_NEVER);

35. How are Date serialized in JSON

JSON doesn't fix a standard for Date serialization unfortunately, so basically it is up to the de-/serializer to produce a format that it will be able to parse later.

By default in Velocity Date are serialized in JSON using this notation:
date: new Date(1352353269039)
(where the digits here are the number of milliseconds since the epoch - January 1, 1970, 00:00:00 GMT in this case Thu Nov 08 00:41:09 EST 2012), this makes it easy to make a date out of this in JavaScript since you can eval that.

But some web services expect dates in a different format.
So since version 2.1, you can tell Velocity and VelocityReport to produce a different format by using a 'jsonDateFormat' default report parameter.
Simply call plugins.VelocityReport.addDefaultReportParameter('jsonDateFormat', JSONDATECONSTANT), and in Velocity, you can use that same property in a Solution object.

There is a JSONDATE constant object that lists the available formats they are:

  • JSONDATE.INTERNAL: new Date(1352353269039)
  • JSONDATE.ISO8601: "2012-11-09T12:40:59.031"
  • JSONDATE.DOTNET: "/Date(1352482888372)/"

You can also add the time offset (relative from the user time zone), by adding JSONDATE.OFFSET to your format, which will add the time offset relative to UTC/GMT:

  • JSONDATE.INTERNAL+JSONDATE.OFFSET: new Date(1352353269039+0300)
  • JSONDATE.ISO8601: "2012-11-09T12:40:59.031+0300"
  • JSONDATE.DOTNET: "/Date(1352482888372+0300)/"
If you don't want Velocity to take care of serializing your dates, you can use
  • JSONDATE.NONE
    But in that case you will have to format your dates as strings yourself in your context object. If Velocity encounters a Date object and this option is used, it will revert to using the java.util.Date.toString() method which result depends on OS and OS settings.

These formats are the most common format used by REST web services.
Of course if you are only using it for internal de-/serialization, you can keep the default or use JSONDATE.OFFSET if you want to use the internal and keep the time zone offset.

In any case, the JSON deserializer will recognize and parse correctly any of these formats, whatever the format you've chosen to serialize it.

In Velocity, you can set the serialization date format to be used in JSON by setting the property jsonDateFormat in your solution object in config.json to one of the values:
  • jsonDateFormat: "internal"
  • jsonDateFormat: "offset"
  • jsonDateFormat: "internal+offset"
  • jsonDateFormat: "iso8601"
  • jsonDateFormat: "iso8601+offset"
  • jsonDateFormat: "dotnet"
  • jsonDateFormat: "dotnet+offset"
  • jsonDateFormat: "none"