You know how you always put a big list of fancy things you want to explore right after attending an Oracle APEX conference? I am not an exception and my list is rather big I must admit. After attending Apex Alpe Adria in Zagreb back in April and listening to Tim Kimberl, one topic topped my list. And it did it again after KScope23 in Aurora back in June.
Template Components
Yes, Template Components
are in my opinion something that puts APEX on another level - but why?
First of all, it allows developers to create reusable components. So that they can be used on multiple pages in multiple applications and by multiple developers - while preserving their style consistently without much effort.
One of their main features is to allow the use of
Template Directives
. They have been available in some APEX regions for a while, as the list of supported regions grows with every version of APEX. I will share a link to what Template Directives are at the end of this article. But in short - they allow developers to use conditional logic with their HTML, moving some complexity out of the SQL and PL/SQL code, putting an end to outputting raw HTML strings out of database procedures and functions and thus preventing any vulnerabilities associated with it. Last but not least - making your code look clean and separating business logic and data from UI and presentation logic.Template Components (and Template Directives in particular) allow nesting. So I can easily reference existing Template Components inside any new components that I am building. This is also valid for the built-in components like Cards, Badges, Avatars, etc.
They can be used as a
Single
standalone component (orPartial
) and as part ofMultiple
-rowReport
. This is defined in the Template Component settings - sometimes it makes sense to have your template available in both forms. That's exactly what I selected for my first one.
My component - BBC style match results
Having explored some of the possibilities of this new APEX feature, I targeted some existing internal apps that could benefit from transforming Dynamic Content
regions into Template Components
. But before doing so, I needed a POC to test my skills and use as many of the Template Components as possible.
As a big fan of football, I decided that something in this domain would be best fit for the purpose. So there we go - The BBC component for displaying matchday results and goal scorers. It would be great as a standalone region (Partial) and in a Report (when displaying all the results for a matchday or a week for example). Here's how it looks on the BBC website:
This is perfect for a first APEX Template Component, as it looks fairly simple, can be used in both forms and can benefit from some more complex logic like conditional statements, loops or being part of a nested component.
Creating the component
Inspect the BBC website and get the HTML code that renders a single match result. Here I hit the first rock, because it seems it was created using
React
and as one can expect, 3 lines of code could turn into 30, full ofdata
attributes and meaninglessCSS classes
. Take a look at this for example, it is the part that displays the goalscorer for Arsenal against Manchester City - Martinelli (86'):<ul class="sp-c-fixture__player-action sp-c-fixture__scorers sp-c-fixture__scorers-home gel-brevier gel-1/2"" data-reactid=".2b5r1dat33i.2.0.0.2.0.$0Premier LeagueSunday-8th-October.2.$EFBO2367608-wrapper.0.0.1.0.0.0"> <li data-reactid=".2b5r1dat33i.2.0.0.2.0.$0Premier LeagueSunday-8th-October.2.$EFBO2367608-wrapper.0.0.1.0.0.0.0:$home0false"> <span data-reactid=".2b5r1dat33i.2.0.0.2.0.$0Premier LeagueSunday-8th-October.2.$EFBO2367608-wrapper.0.0.1.0.0.0.0:$home0false.0">Martinelli</span> <span data-reactid=".2b5r1dat33i.2.0.0.2.0.$0Premier LeagueSunday-8th-October.2.$EFBO2367608-wrapper.0.0.1.0.0.0.0:$home0false.1:0">(</span> <span data-reactid=".2b5r1dat33i.2.0.0.2.0.$0Premier LeagueSunday-8th-October.2.$EFBO2367608-wrapper.0.0.1.0.0.0.0:$home0false.1:$0"> <span data-reactid=".2b5r1dat33i.2.0.0.2.0.$0Premier LeagueSunday-8th-October.2.$EFBO2367608-wrapper.0.0.1.0.0.0.0:$home0false.1:$0.0">86'</span> <span class="gs-u-vh" data-reactid=".2b5r1dat33i.2.0.0.2.0.$0Premier LeagueSunday-8th-October.2.$EFBO2367608-wrapper.0.0.1.0.0.0.0:$home0false.1:$0.1">minutes</span> <span data-reactid=".2b5r1dat33i.2.0.0.2.0.$0Premier LeagueSunday-8th-October.2.$EFBO2367608-wrapper.0.0.1.0.0.0.0:$home0false.1:$0.2"></span> </span> <span data-reactid=".2b5r1dat33i.2.0.0.2.0.$0Premier LeagueSunday-8th-October.2.$EFBO2367608-wrapper.0.0.1.0.0.0.0:$home0false.1:2">)</span> <span data-reactid=".2b5r1dat33i.2.0.0.2.0.$0Premier LeagueSunday-8th-October.2.$EFBO2367608-wrapper.0.0.1.0.0.0.0:$home0false.2"></span> </li> </ul>
Ugly, right? Very ugly, indeed! So I needed to clean it out and only use a much lighter version in my Template Component:
<ul class="sp-c-fixture__player-action sp-c-fixture__scorers sp-c-fixture__scorers-home gel-brevier"> {if ?SHOW_SCORERS/} {loop "|" HOME_TEAM_SCORERS/} <li><span>&APEX$ITEM.</span></li> {endloop/} {endif/} </ul>
Here, by the way, we already see some of the cool stuff:
{if ?SHOW_SCORERS/}
means that the block will only be displayed if the value is not null or empty. And later on I can control this using an item on my page to toggle between both states - displayed or not.{loop "|" HOME_TEAM_SCORERS/}
will go through the string with home team goal scorers and create a separate<li>
element for each of them. As seen, they are divided by a "|". A sample goalscorers string in my region or report should look like this: Plamen Mushkov (51')|Zlatan Ibrahimovic (70')-- Plamen Mushkov (51')|Zlatan Ibrahimovic (70') select LISTAGG(scorer, '|') WITHIN GROUP (ORDER BY goal_time asc) home_team_scorers from games group by game_id, team_id
Inspect the BBC website and get the CSS code - it's again a tricky task, as the CSS in this case was not put in a special file, but was generated inline in the HTML of the page. It also had a lot of unnecessary classes, that I had to clean. One last step is that I moved the colours to separate CSS variables, so I can change them in only one place if needed, but above all - to make it possible for edit by the Template Component users some day if I decided to.
Insert placeholders in my HTML Template like so:
{if ?GAME_URL/} <a class="sp-c-fixture__block-link" href="#GAME_URL#"> {endif/} <article class="sp-c-fixture"> <div class="sp-c-fixture__wrapper"> ... </div> </article> ... {if ?GAME_URL/} </a> {endif/}
Checking the details of my Custom Attributes - yes, they are
auto-detected
and created, based on theplaceholders
in your HTML template. But you can still addHelp
text, addExamples
orDefault Values
or change theirDatatype
.
Before going into the implementation part - do yourself a favour and explore the options you have on the Template Component Plug-ins. Sometimes the only way to learn is to experiment, so do it.
Another advice would be to download and explore the Template Component Plug-ins that are publically available - the Demo app that Tim demonstrated, the Sample app on Template Directives by Jorge, the videos and blogs from Philipp, Jon and Matt (sorry if I'm missing someone) and the plugin section of apex.world, now providing a separate category for Template Components (I told you it's a huge thing, right!).
Using my new BBC Result Template Component
The Demo that I prepared consists of three elements - a Page Item
(toggle) to allow users to hide/show goal scorers, an Application Component
Type region (Single) "BBC Results" to display a single game and an Interactive Report
with a column of an Application Component
Type "BBC Results".
The Single type component
select 'CSKA Sofia' home_team, 3 home_team_score,
'Plamen Mushkov (15'')|Plamen Mushkov (62'')|Plamen Mushkov (70'')' home_team_scorers,
'Levski Sofia' away_team, 1 away_team_score,
'Ricardinho (29'')' away_team_scorers,
'FT' game_state, null game_url,
decode(:P37_SHOW_SCORERS,'N',null,:P37_SHOW_SCORERS) show_scorers
from dual
The Interactive Report
select 'Arsenal' home_team, 1 home_team_score,
'Manchester City' away_team, 0 away_team_score,
'FT' game_state, null game_url,
'Martinelli (86'')' home_team_scorers,
null away_team_scorers,
decode(:P37_SHOW_SCORERS,'N',null,:P37_SHOW_SCORERS) show_scorers,
null result from dual union all
select 'Brighton' home_team, 2 home_team_score,
'Liverpool' away_team, 2 away_team_score,
'FT' game_state, '#' game_url,
'Adingra (20'')|Dunk (78'')' home_team_scorers,
'Salah (40'', 45''+1 pen)' away_team_scorers,
decode(:P37_SHOW_SCORERS,'N',null,:P37_SHOW_SCORERS) show_scorers,
null result from dual union all
select 'West Ham' home_team, 2 home_team_score,
'Newcastle' away_team, 2 away_team_score,
'FT' game_state, '#' game_url,
'Soucek (8'')|Kudus (89'')' home_team_scorers,
'Isak (57'', 62'')' away_team_scorers,
decode(:P37_SHOW_SCORERS,'N',null,:P37_SHOW_SCORERS) show_scorers,
null result from dual
Final result
You can see the final Demo here:
https://apex.oracle.com/pls/apex/r/gamma_dev/demo/bbc-results
Learning Resources
Thanks to the efforts of the APEX Development team, as well as the awesome community we have, it's very easy to get started with Template Components. Here are the resources I would recommend you to get started with:
๐ http://timplating.com/ - a collection of Demo apps, built by Tim Kimberl, a member of the APEX Development team. I recommend you explore the
Metric Card Demo
andUT 23.1 Template Components
apps to see what a good template component looks like.๐ https://rimblas.com/blog/presentations/ and Template Directives Demo App - an awesome Demo application by Jorge Rimblas, with sample code included, showcasing conditional Template Directives (a core part of the Template Components), loops, etc.
๐ https://mattmulvaney.hashnode.dev/the-thought-process-involved-in-the-creation-of-apex-template-components - a Step-by-step guide on creating a Template Components by Matt Mulvaney I guarantee you will have a working component in less than an hour if you follow that guide along.
๐ https://hartenfeller.dev/blog/oracle-apex-template-components-introduction - another Step-by-step guide by Philipp Hartenfeller on creating Template Components, also explaining Actions (another good use case for Template components).
๐ https://blog.cloudnueva.com/leveraging-apex-theme-components - A blog post by Jon Dixon, which explains the built-in Template (or Theme) Components like Badges, Avatars, Comments, etc. In another blog post - https://blog.cloudnueva.com/apex-template-directives - he explains some of the features that Template Directives can offer.
๐ Oracle's Documentation on Template Directives: https://docs.oracle.com/en/database/oracle/apex/23.1/htmdb/using-template-directives.html
๐ http://apex.world/ - the Plug-in section of apex.world where you can find a number of community built Template Components, free to use and learn from. Just filter on
Plug-in type
and pickTemplate Components
.
Template Component Challenge
Join the Template Component Plugin Challenge - deadline October 31st.
Read more about it here: https://apex.mt-itsolutions.com/ords/r/portal/apex/template-component-challenge
Follow me
Don't forget to follow me on Hashnode, Wordpress and social media. I will soon publish my Template Component to apex.world so you can download it and use it inside your applications too.