BBC's guide to development
  • General

    • About
    • Tools
    • Git(hub)
    • Showpad
    • Hosting
    • Maintenance
    • Security
    • Go live checklist
  • Front-end development

    • Bundlers
    • CSS/SCSS
    • Javascript
    • Vue
    • PHP
    • Mails
    • Dev Faq
  • Functions
  • Mixins
  • General

    • OOP Structure
  • Component Classes

    • Accordion
    • App
    • Component
    • HighwayApp
    • Popup
    • PNG Sequencer
    • Tab
  • Manager Classes

    • BountListenerMgr
    • Cache
    • Configuration
    • InViewStateMgr
    • Instance Manager
    • Event dispatcher
  • Factories

    • SwiperFactory
  • PDF

    • AssetLoader
    • BasePdfDoc
    • TemplatePdfDoc
    • CustomPdfDoc
  • Utility functions

    • canvas
    • Connection Status
    • css
    • dev
    • placeholder
    • dom
    • fetch
    • json
    • object
    • scroll
    • scrollbar
    • spreadsheets
    • string
    • url
  • General

    • ComponentMgr
    • ThreeJsViewer
  • Components

    • ComponentMgr
    • GltfModel
    • Snappable
    • Socket
    • ThreeJsViewer
    • ThreeJsViewerCamera
  • Loaders

    • ConfigurationSerializer
    • GltfBlockParser
  • Utils

    • CanvasInputAdapter
    • CollisionManager
    • SocketGridExpander
    • blender
    • headless
  • General

    • Troubleshooting
    • Legacy
  • Components

    • AssetBar
    • ConfigGenerator
    • ShowpadApp
  • Managers

    • Assets
    • AppsDb
    • Config
  • Utils

    • Connection Status
    • general
    • showpad-interactive
    • showpad-upload
  • Components

    • Accordion
    • BackButton
    • Breadcrumb
    • ByltButton
    • Hamburger
    • Icon
    • Logo
    • Loader
    • Modal
    • Popup
    • Prompt
    • ProgressBar
    • TextLoader
  • Composables

    • useDebugMode
    • useConnectionStatus
  • Utils

    • dom
    • props
  • General

    • General
    • Tracking
  • Components

    • Accordion
    • ActionButton
    • AssetItem
    • AssetList
    • BackButton
    • ConfigGenButton
    • Logo
    • Media
    • Modal
    • Popup
    • Prompt
    • SPButton
    • SPRouterView
    • SPTrackedRouterLink
    • TextLoader
    • View
  • Composables

    • useConnectionStatus
  • Stores

    • useAppsDbStore
    • useBreadcrumbStore
    • useShowpadAPIStore
    • useShowpadSDKStore
    • useSpConfigStore
    • useSpStore
    • useSpTrackingStore
  • The New Kit

    • General
    • Installation & Usage
    • ACF Blocks
    • PHPCS
    • Functions
    • Vite
    • WP Config
    • Staging Deployment
  • Best Practices

    • Page Structure
    • Fonts/Typography
  • Todo
GitHub
  • General

    • About
    • Tools
    • Git(hub)
    • Showpad
    • Hosting
    • Maintenance
    • Security
    • Go live checklist
  • Front-end development

    • Bundlers
    • CSS/SCSS
    • Javascript
    • Vue
    • PHP
    • Mails
    • Dev Faq
  • Functions
  • Mixins
  • General

    • OOP Structure
  • Component Classes

    • Accordion
    • App
    • Component
    • HighwayApp
    • Popup
    • PNG Sequencer
    • Tab
  • Manager Classes

    • BountListenerMgr
    • Cache
    • Configuration
    • InViewStateMgr
    • Instance Manager
    • Event dispatcher
  • Factories

    • SwiperFactory
  • PDF

    • AssetLoader
    • BasePdfDoc
    • TemplatePdfDoc
    • CustomPdfDoc
  • Utility functions

    • canvas
    • Connection Status
    • css
    • dev
    • placeholder
    • dom
    • fetch
    • json
    • object
    • scroll
    • scrollbar
    • spreadsheets
    • string
    • url
  • General

    • ComponentMgr
    • ThreeJsViewer
  • Components

    • ComponentMgr
    • GltfModel
    • Snappable
    • Socket
    • ThreeJsViewer
    • ThreeJsViewerCamera
  • Loaders

    • ConfigurationSerializer
    • GltfBlockParser
  • Utils

    • CanvasInputAdapter
    • CollisionManager
    • SocketGridExpander
    • blender
    • headless
  • General

    • Troubleshooting
    • Legacy
  • Components

    • AssetBar
    • ConfigGenerator
    • ShowpadApp
  • Managers

    • Assets
    • AppsDb
    • Config
  • Utils

    • Connection Status
    • general
    • showpad-interactive
    • showpad-upload
  • Components

    • Accordion
    • BackButton
    • Breadcrumb
    • ByltButton
    • Hamburger
    • Icon
    • Logo
    • Loader
    • Modal
    • Popup
    • Prompt
    • ProgressBar
    • TextLoader
  • Composables

    • useDebugMode
    • useConnectionStatus
  • Utils

    • dom
    • props
  • General

    • General
    • Tracking
  • Components

    • Accordion
    • ActionButton
    • AssetItem
    • AssetList
    • BackButton
    • ConfigGenButton
    • Logo
    • Media
    • Modal
    • Popup
    • Prompt
    • SPButton
    • SPRouterView
    • SPTrackedRouterLink
    • TextLoader
    • View
  • Composables

    • useConnectionStatus
  • Stores

    • useAppsDbStore
    • useBreadcrumbStore
    • useShowpadAPIStore
    • useShowpadSDKStore
    • useSpConfigStore
    • useSpStore
    • useSpTrackingStore
  • The New Kit

    • General
    • Installation & Usage
    • ACF Blocks
    • PHPCS
    • Functions
    • Vite
    • WP Config
    • Staging Deployment
  • Best Practices

    • Page Structure
    • Fonts/Typography
  • Todo
GitHub
  • Showpad App

Showpad App

import ShowpadApp from '@bbc/front-end-kit/js/components/ShowpadApp';

Most of our Showpad Applications use Highway js as a router. Therefore this class extends from our HighwayApp class to benefit from our common setup for Highway routed applications. This class adds all the necessary preparation logic for Showpad applications so that there is no need to go through the initial setup with library loading, config loading and config injection and repeating all that every time the view changes. It provides us with a generic and consistent way to set this up so that it improves maintainability and project transportability between devs.

Getting started

Just like App and HighwayApp, it is meant to be extended and use that child class as the base of the project that is being developed

export default class MainApp extends ShowpadApp {

    // constructor
    constructor(args = {}) {
        // call super
        super(_defaultsDeep(args, {
            showpad: { /* ShowpadApp configuration */ },
            /* HighwayApp configuration */
            /* Media query definitions */
        }));
    }

    // methods...
}

Initialisations

Like HighwayApp adds initialisation keys, ShowpadApp does too. This way it is possible to run logic during every step of the config loading/injection/building process

  • showpad:lib-loaded: When Showpad's library is loaded
  • showpad:user-loaded: When the current user's info has been fetched
  • showpad:config-loaded: When Showpad's config.json is loaded into memory
  • showpad:config-injected: When config injection into the DOM has happened (also fires on every Highway page change)
initReadyView(args = {}) {
    // block method when key is not...
    if (![
        'init:resize',                  // on resize
        'showpad:config-injected'       // after config injected => happens on highway page changes too
    ].includes(args.key)) return

    // run inits
}

Highway settings

An extra Highway setting is added that is purely made for developement. It is the index property.

export default class MainApp extends ShowpadApp {

    // constructor
    constructor(args = {}) {
        // call super
        super(_defaultsDeep(args, {
            highway: {
                index: '/'
            }
        }));
    }

    // methods...
}

Automatic Development Redirection

In our structure of developing for Showpad, it may be required to alway pass through the index in order to make sure everything initialised properly. Something that may not happen when development is happening on a sub page. This property will force the application to go redirect using a page load to the index and then redirect back to the originally requested page using the Highway router.

This way sub-pages don't need to have all the globally defined components in HTML and still show them as if they were thanks to the fact the redirection through Index happens.

Tips

This option can be disabled using preventDevRedirect in the showpad constructor object.

// class
export default class MainApp extends ShowpadApp {

    // constructor
    constructor(args = {}) {

        // call super
        super(_defaultsDeep(args, {

            showpad: {
                preventDevRedirect: false,
            },

        }));
    }

    //...
}

Automatic AppsDb initialisation

The instance provides the ability to automatically initialise AppsDb stores using our AppsDb class by default. This can be overridden if the custom class is provided. Mind that it will always look for the init() method.

export default class MainApp extends ShowpadApp {

    // constructor
    constructor(args = {}) {
        // call super
        super(_defaultsDeep(args, {
            showpad: { 
                appsDbKeys: [
                    { id: 'appsdb-local-store-id', type: 'local' },
                    { id: 'appsdb-global-store-id', type: 'global' },
                    { id: 'appsdb-custom-local-store-id', type: 'local', Class: CustomAppsDbClass },
                    { id: 'appsdb-custom-global-store-id', type: 'global', Class: CustomAppsDbClass },
                ]
            },
        }));
    }

    // methods...
}

Build-in placeholder methods

Showpad App comes with some built-in Config methods that are automatically added bo the constructor args. These are complex, yet very handy when it comes to implementing ShowpadConfig configuration paths.

Placeholders can be defined for both javascript value retrievals and DOM value injections.

path

This provides the ability add regions to your HTML and let the config use them to generate the paths to the config values, shortening the define paths and greatly reducing the changes for mistakes at a slight cost of added complexitiy. It introduces a new data attribute: data-sp-region to define those regions in html.

DOM Injections only!

<div data-sp-region="region-1"></div>
    <div data-sp-region="region-2"></div>
        <div data-sp="{{ path }}.title"></div>
    </div>
</div>

Will result in injecting the value in the html that was found on
[labels/content].region-1.region-2.title.value

generalPath

Produces a path prefixed with general. followed by the data-sp-region chain of the element, e.g. general.region-1.region-2. Useful for config values that live under a shared general namespace rather than a view-specific path.

DOM Injections only!

<div data-sp-region="footer">
    <span data-sp="{{ generalPath }}.cta-label"></span>
</div>

Will look up: [labels/content].general.footer.cta-label.value

i and i-*

This provides the ability to keep track of the index of the item it is applied to. DOM Injections only!

  • i-*: Same as ì although it uses the * as a number or a key to alter the classic way of counting.
    • i-[level]: Define the amount of levels it needs to go up in the dom and start counting from there. Handy for elements that are nested inside a wrapper but need to use the index of their parent wrapper
    • i-[region]: Region key to use as counter id. Uses data-sp-region keys as counter ids just like CSS does. data-sp-region 'resets' the counter of that region, all items using that key will increase the counter by 1 everytime the key is used as placeholder in the config path.
    • i: If no key or level is given, it will use the current region as the active counter.

Level example:

    <ul>
        <li>
            <span data-sp="list.item-{{ i-1 }}"></span>
        </li>
        
        <li>
            <span data-sp="list.item-{{ i-1 }}"></span>
        </li>
        <li>
            <span data-sp="list.item-{{ i-1 }}"></span>
        </li>
    </ul>

Will result in injecting the value in the html that was found on:

  • [labels/content].list.item-1.value
  • [labels/content].list.item-2.value
  • [labels/content].list.item-3.value

Region example:

    <ul data-sp-region="list">
        <li>
            <span data-sp="list.item-{{ i-list }}"></span>
        </li>
        
        <li>
            <span data-sp="list.item-{{ i-list }}"></span>
        </li>
        <li>
            <span data-sp="list.item-{{ i-list }}"></span>
        </li>
    </ul>

Will result in injecting the value in the html that was found on:

  • [labels/content].list.item-1.value
  • [labels/content].list.item-2.value
  • [labels/content].list.item-3.value

It goes up a parent and starts to count the index from that parent.

Combination example

An example of combining both built-in placeholders

<div class="content" data-sp-region="page">

    <ul class="list-1" data-sp-region="list-1">
        
        <li class="list-1__item"> <span data-sp="{{ path }}.item-{{ i }}"></span></li>

        <li class="list-1__item">
            <span data-sp="{{ path }}.item-{{ i }}"></span>
            <ul class="list-2" data-sp-region="list-2">
                <li class="list-2__item"><span data-sp="{{ path }}.item-{{ i }}"></span></li>
                <li class="list-2__item"><span data-sp="{{ path }}.item-{{ i }}"></span></li>
            </ul>
        </li>

        <li class="list-1__item"> <span data-sp="{{ path }}.item-{{ i }}"></span></li>

        <li class="list-1__item">
            <span data-sp="{{ path }}.item-{{ i }}"></span>
            <ul class="list-2" data-sp-region="list-2">
                <li class="list-2__item"><span data-sp="{{ path }}.item-{{ i-list-1 }}-{{ i }}"></span></li>
                <li class="list-2__item"><span data-sp="{{ path }}.item-{{ i-list-1 }}-{{ i }}"></span></li>
            </ul>
        </li>
    </ul>

</div>   

Will result in injecting the value in the html that was found on:

  • [labels/content].page.list-1.item-1.value
  • [labels/content].page.list-1.item-2.value
  • [labels/content].page.list-1.list-2.item-1.value
  • [labels/content].page.list-1.list-2.item-2.value
  • [labels/content].page.list-1.item-3.value
  • [labels/content].page.list-1.item-4.value
  • [labels/content].page.list-1.list-2.item-4-1.value
  • [labels/content].page.list-1.list-2.item-4-2.value

API

constructor(args = {})

The constructor method initialises the new ShowpadApp instance.

Parameters

  • args: The configuration object used by the constructor to initialise the ShowpadApp in the desired way.
    • showpad: Contains the settings for the ShowpadApp instance
      • appsDbKeys: Array of AppsDb definition objects. Each entry is passed directly to new (def.Class || AppsDB)(def), so any AppsDb constructor argument (id, type, accessToken, oauthInstance, …) can be set per entry. init() is called on each only when the current user is an admin.
      • configGen: Activates the config builder on every page- and view-load.
      • placeholders: Placeholder value & method logic that will be passed to the ShowpadConfig instance.
      • preventDevRedirect: Disables the rediraction through index (on page refresh) during development
    • highway: Contains the settings for the HighwayApp instance (parent of ShowpadApp)
      • index: Sets the index to redirect from when developing on a sub page, this way we don't need to navigate back to the page that is being developed. (addition by ShowpadApp!)
      • devRedirectTimeout (number, default 500): Milliseconds to wait before Highway redirects back to the originally-requested page after the dev redirect through index.
    • mediaQueries: The mediaquery definition collection it needs to initialise for

Methods

navigateIn(args = {})

If present, it will be called when Highway's Navigate_IN' is fired. Args object contains the information from the Highway event.

Tips

Make sure to call super.navigateIn() when extended.

navigateOut(args = {})

If present, it will be called when Highway's Navigate_OUT is fired. Args object contains the information from the Highway event.

Tips

Make sure to call super.navigateOut() when extended.

navigateEnd(args = {})

If present, it will be called when Highway's Navigate_END is fired. Args object contains the information from the Highway event.

Tips

Make sure to call super.navigateEnd() when extended.

Getters & Setters

Showpad

The Showpad library instance the ShowpadApp is using

showpadConfig

The ShowpadConfig instance the app is using.

configGen

Boolean signaling if the config is generated on every pageload and view load.

configLoaded

Boolean signaling that the config is loaded in the ShowpadConfig instance.

Public properties

user

The current Showpad user object, populated automatically after Showpad.getUserInfo() resolves. Contains at minimum id, full_name, and isAdmin (boolean — set to true only when online and the user is confirmed as admin).

Private properties

_appsDbs

Instances of the AppsDbs it has initialised during loading

_configGen

Boolean flag to activate Config object generation on page load.

_showpadConfig

The Config instance it uses for Showpad config loading & dom injection.

External dependencies

This class uses some external dependencies that may be necessary to install using NPM.

  • Experience APP SDK: Showpad's library
  • lodash: For some quick and usefull utility methods like:
    • capitalize: To capitalize strings so that init[name] can be written in camelCase
    • defaultsDeep: Used to provide objects with default values.
    • camelCase: Turns strings into camel case casing.
    • kebabCase: Turns strings into kebab case casing.

Todo

  • Use named methods for specific but reocurring scenarios instead of having to use checks on each method.
  • Separate Built-in placeholder methods to utils file so they are ready to be reused in other scenarios
Edit this page
Last Updated: 4/27/26, 12:56 PM
Contributors: Nicolas Jaenen