How I created my first APEX Template Component

How I created my first APEX Template Component

ยท

8 min read

Play this article

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 (or Partial) and as part of Multiple-row Report. 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

  1. 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 of data attributes and meaningless CSS 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&quot;"
         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
      
  2. 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.

  3. 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/}
    
  4. Checking the details of my Custom Attributes - yes, they are auto-detected and created, based on the placeholders in your HTML template. But you can still add Help text, add Examples or Default Values or change their Datatype.

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:

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

Template Component Plugin 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.

ย