Skip to content

monstermichl/HandlebarsABAP

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

49 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

HandlebarsABAP

Single-file 7.40 SP02 Handlebars implementation for ABAP.

What is Handlebars?

To quote the Handlebars documentation:

Handlebars is a simple templating language. It uses a template and an input object to generate HTML or other text formats. Handlebars templates look like regular text with embedded Handlebars expressions.

<p>{{firstname}} {{lastname}}</p>

A handlebars expression is a {{, some contents, followed by a }}. When the template is executed, these expressions are replaced with values from an input object.

Why Handlebars for ABAP?

Even though the WWW_HTML_MERGER function module exists to load and merge HTML templates with simple data, it is very limited in its use. Handlebars on the other hand allows for building highly flexible templates and automatically resolves deeply nested structures and tables, making it easy to quickly build extremely customizable HTMLs/texts based on its input data.

To compile a Handlebars template, simply pass it to the static compile-method and call the returned instance's template-method to fill the template with the provided data.

TYPES: BEGIN OF ts_title,
         front TYPE string,
         back  TYPE string,
       END OF ts_title.

TYPES: BEGIN OF ts_person,
         title     TYPE ts_title,
         firstName TYPE string,
         lastName  TYPE string,
       END OF ts_person.

" Compile the Handlebars template.
DATA(ls_compile_result) = zcl_handlebars_abap=>compile(
  '{{#if title.front}}' &
    '{{title.front}} ' &
  '{{/if}}' &

  '{{firstName}} {{lastName}}'
).

" Create a structure.
DATA(ls_person) = VALUE ts_person(
  title = VALUE #( front = 'Ing.' back = 'BSc.' ) firstName = 'Peter' lastName = 'Parker'
).

" Let the magic happen.
DATA(ls_template_result) = ls_compile_result-instance->template( ls_person ).

WRITE / ls_template_result-text. " Prints 'Ing. Peter Parker'.

Installation

HandlebarsABAP can be installed by using the latest release-tag via abapGit or by simply creating a ZCL_HANDLEBARS_ABAP-class on the client and pasting the content of the latest ZCL_HANDLEBARS_ABAP.abap release file into it.

Stored templates

To compile a template stored via transaction SMW0, just pass the template name to compile. It is recommended to store the HTML-template as binary data in SMW0. Not storing it as binary data could lead to a wrong interpretation of language specific letters (e.g. ä, ö, ü, ß, ...). Even though templates stored as HTML are still supported, templates stored as binaries take precedence and are converted to UTF-8.

What's supported so far

Fields

{{title.front}} {{firstName}} {{lastName}} {{title.back}}

Block helpers

Builtin

if
{{#if condition}}
  render something
{{else}}
  render something else
{{/if}}
unless
{{#unless condition}}
  render something
{{else}}
  render something else
{{/unless}}
each
{{#each people}}
  {{this.firstName}}
{{else}}
  No person found
{{/each}}
with
{{#with person}}
  {{this.firstName}}
{{else}}
  No person found
{{/with}}

Inline helpers

Builtin

log
{{log "Hello World"}}

Block parameters

{{#each people as |person index|}}
  {{index}}: {{person.firstName}}
{{else}}
  No person found
{{/each}}

Sub expressions

{{#if (log "Hello World")}}
  what?
{{else}}
  log didn't return anything
{{/if}}

Custom (block) helpers

It's possible to write and configure custom helpers like in HandlebarsJS but it works a bit differently. In HandlebarsJS a fn- and a reverse-function is passed to the helper which then need to be called to render either the block-content or the else-content. Since ABAP does not allow to pass functions to other functions or methods, the corresponding functions are part of the zcl_handlebars_abap class. The instance of the class gets passed to the helper and the helper needs to either invoke fn or reverse on that instance. The first argument that's passed to the corresponding function is considered the new context within the block (this).

METHOD hello.
  ASSIGN it_args[ 1 ]->* TO FIELD-SYMBOL(<name>).

  rs_result = io_instance->fn( NEW string( |Hello { <name> } | ) ).
ENDMETHOD.

How to handle data

Each helper function receives an it_args table as argument. This table contains references to the data passed, which could be a struct, a table or something simple like bool, int, string...

It's the implementer's responsibility to handle the data correctly. To get a feeling how to implement helpers it can be useful to have a look into backend_eval_cond_helper/backend_eval_each_helper/backend_eval_with_helper.

What to return

The rs_result's text-property specifies, what will be rendered to the output. If something went horribly wrong the rs_result's error-property must be set. This will halt further template execution and will propergate the error up to the end result.

Custom-helper helper-methods

  • is_truthy: Returns abap_true if the passed data evaluates to something that is considered truthy by HandlebarsJS standars.
  • error: Creates an error string that contains the position where the error occurred.

How to register a custom helper

To register a custom helper there are two possible ways. Either globally, directly on the zcl_handlebars_abap class or on an instance which gets returned calling compile. Globally configured helpers get added to the instances created. However, helpers registered on the instances take precedence.

register_helper( iv_name = 'hello' ir_helper = NEW zcl_handlebars_abap=>ts_object_helper( object = lo_helper_object method_name = 'hello_helper' ) ).

Function/Method signatures

Helper functions/methods get passed the following properties:

  • instance: The instance of the currently processed object on which to call fn/reverse.
  • name: The name of the registered helper. This can be useful if method gets registered for different helper names.
  • args: The arguments passed to the helper.
  • data: The current data of the block.
(Class-)methods

This is the prefered way to implement helpers as it goes hand in hand with the modern approach of ABAP programming. Both static and object methods must implement the following signature to be callable.

METHODS helper_method
  IMPORTING
    io_instance      TYPE zcl_handlebars_abap
    iv_name          TYPE string
    it_args          TYPE zcl_handlebars_abap=>tt_data
    ir_data          TYPE zcl_handlebars_abap=>tr_data
  RETURNING
    VALUE(rs_result) TYPE zcl_handlebars_abap=>ts_text_result.

To register a class-method, use the ts_class_helper structure. E.g.

register_helper( iv_name = 'hello' ir_helper = NEW zcl_handlebars_abap=>ts_class_helper( class_name = 'ZCL_HELPER_CLASS' method_name = 'hello_helper' ) ).

To register an object-method, use the ts_object_helper structure. E.g.

register_helper( iv_name = 'hello' ir_helper = NEW zcl_handlebars_abap=>ts_object_helper( object = lo_helper_object method_name = 'hello_helper' ) ).

Function modules

A function module must implement the following signature to be callable.

FUNCTION helper_method
  IMPORTING
    io_instance TYPE zcl_handlebars_abap
    iv_name     TYPE string
    it_args     TYPE zcl_handlebars_abap=>tt_data
    ir_data     TYPE zcl_handlebars_abap=>tr_data
  EXPORTING
    es_result   TYPE zcl_handlebars_abap=>ts_text_result.

To register a function module, use the ts_func_module_helper structure. E.g.

register_helper( iv_name = 'hello' ir_helper = NEW zcl_handlebars_abap=>ts_func_module_helper( function_name = 'ZCL_HELLO_HELPER' ) ).

Forms

A form must implement the following signature to be callable.

FORM helper_method
  USING
    io_instance TYPE zcl_handlebars_abap
    iv_name     TYPE string
    it_args     TYPE zcl_handlebars_abap=>tt_data
    ir_data     TYPE zcl_handlebars_abap=>tr_data
  CHANGING
    cs_result   TYPE zcl_handlebars_abap=>ts_text_result.

To register a form, use the ts_form_helper structure. E.g.

register_helper( iv_name = 'hello' ir_helper = NEW zcl_handlebars_abap=>ts_form_helper( report_name = 'Z_HELLO_HELPER' form_name = 'hello_helper' ) ).

About

Single-file Handlebars implementation for ABAP

Topics

Resources

License

Stars

Watchers

Forks

Contributors

Languages