Built from html, javascript, css, standard unified-ux web components and a single additional (demo-specific) <uwc-onboard-customer> web component, the main focus of this demo is on integrating with various Transact API-related services (as described on the Temenos API Portal) to implement a simple "customer onboarding" process.

The first time you access it, the demo application will prompt you for an "API key". This is a (user-specific) security token serving as authentication for each Transact API request.

If you don't already have one, the steps for obtaining an API key are explained here.

On successful submission of your API key, the demo application will store this as a cookie (re-prompting you for a new one on subsequent visits only in the event that the previously stored key has now expired).

You can access the demo application directly (vs. downloading/building/running locally) via the following link:

Transact API Demo (opens in a new tab/window)

  1. To see what's going on behind the scenes (especially, the actual requests/responses sent to / received from the Transact API endpoints), we'd recommend opening your browser's debugger (either in a new window, or docked to the right of the demo tab/window), arranging things such that you can observe the console output as you perform actions within the application.

  2. At the point where you're initially prompted for your API key, you might first try deliberately entering an invalid one (e.g. WXYZ) to see the API request we dispatch to validate it, the response that we receive, how the application responds to that response, and so forth.

  3. Once you've successfully submitted your (valid) API key, you might like to try:

    • reloading the demo app page (or re-opening the demo app in another tab/window), at which point the demo app should take you directly to the welcome screen (vs. routing you via the API key dialog), having successfully validated the API key from the cookie created on initial submission of your (valid) key

    • you might also try out some of the options under the API key cookie section of the menu accessed via the "settings" icon in the left navigation (e.g. choose "Store EXPIRED key" and then reload the page to see how the application would handle the situation where a previously valid key had been stored as a cookie, but has since expired).

  4. Now let's try accessing the customer onboarding screen by clicking the 2nd icon from the top in the left-hand navigation rail.

    Before we get to filling fields, submitting requests, etc, you might like to try:

    • exercising the "responsive" behaviour by progressively widening / narrowing the amount of screen width available to the form.

      You should see that, when the width is sufficient to allow it, the fields are laid out as 2 columns of "cards" (<uwc-card>(s)) (i.e. 2 cards per row), whereas when the width is reduced beyond a certain point, the layout adjusts to present the cards in a single column (i.e. 1 card per row) with the vertical scrollbar adjusting to accommodate the new height of the content.

      (This behaviour is achieved (within the render() method of our onboard-customer.ts component) by wrapping our <uwc-card> elements in <uwc-grid> elements. For futher information on the <uwc-grid> component, check out the Grid Tutorial item on the left).

    • try out the options found within following sub-sections of the "settings" menu (accessed by clicking the "gear" icon at the bottom of the navigation rail):

      • Layout direction: try switching from Left to right (ltr) to Right to left (rtl) and back
      • Theme: try switching from Temenos to Custom and back
  5. Exercising the client-side validation

    As you may have noticed, 2 of the fields (Language and Sector ) have labels that include a trailing asterisk (*).

    These denote "unconditionally mandatory" fields - i.e. fields for which a value is always required (regardless of the values specified for any other fields)

    Let's begin by hitting Submit button (at the bottom of the screen) straight away, - i.e. without actually entering values for any of the fields.

    At this point you should hopefully see a modal message box inviting you to fix the issues with the (2) fields highlighted in red (Language and Sector).

    Note that this is pure client-side validation (as yet nothing has been POSTed to the Transact API).

  6. Onboarding our first Customer

    Close the modal message box, then:

    • Choose a value (e.g. Admiral) for the Title <uwc-combobox> field

      TIP: Try typing: Ad - the list will be filtered so that Admiral appears as the first entry; you can now press the <DownArrow> key to move focus to that (first) list entry, followed by <ENTER> to select it

    • Now enter something plausible for the First Name and Last Name fields (e.g. Fred and Smith)

      TIP: You can use <TAB> and <SHIFT+TAB> to move forward / backwards to the next / previous field, respectively

    • Move on to the Language field, and choose: English

      Notice how the client-side validation message is automatically cleared on selection of a value (this behaviour is built into <uwc-combobox>)

    • For the Nationality field, type Gr then pick Great Britain

      Notice how, for this list, the display values appeared in ascending alphabetical order

      This is the result of post-processing applied by js/modules/dynamic-list-registry.js in response to "doSortByLabel" : true having been specified for "listName": "country" (in the server-side response, the list entries are actually sorted by list key)

    • Pick 1001 Individual as the value for the Sector field

      Notice how, for this list, each display value (such as Individual) has been prefixed with the corresponding (submittable) "key" (e.g. 1001).

      This is the result of post-processing applied by js/modules/dynamic-list-registry.js in response to"doPrefixLabelsWithValues": true having > been specified for "listName": "sector" in data/dynamic-list-specs.jsn

    • Finally, click the Submit button

      Hopefully you should now see a message box indicating the successful creation of your customer and enumerating the server-side generated values for auto-populatable fields: Customer Name, Display Name and Customer Mnemonic

  7. Provoking some server-side validation errors

    The Customer entity is a complex one having many more fields than are included in this simple demo application, several of which are conditionally mandatory based on the value chosen for the Sector field.

    Try altering the value for Sector to be 141 Indvl/Corprt, then hitting the Submit button.

    NB: Given that (currently) our Submit button always performs a POST (vs the PUT that would be necessary to edit an existing Customer), this will be actually be interpreted by the server as an attempt to create another customer (using the the same data - except for Sector - that we supplied for the previous one).

    Hopefully you should now see a modal message box indicating that server side validation reported 6 errors.

    On closing the modal message box, you should be taken to the top of the screen, where details of those validation errors should now displayed. You'll see that the errors are rendered in 2 different ways:

    • Errors rendered like this: [T24-001] Industry: MISSING CUSTOMER.DEFAULT - RECORD relate to the (relatively small) subset of conditionally mandatory (Sector-dependant) Customer fields that our demo customer onboarding screen actually provides inputs for.

      Notice how, unlike the ones rendered in gray (see below), these feature the field label (vs. the internal field name supplied to us in the server response).

      • Try clicking one of these errors.

        The corresponding field should be scrolled into view and highlighted with a red underbar

      • Try selecting a value for that field and re-submitting the form

        You should see that the number of errors reported is reduced by 1, and that the field you just populated is no longer mentioned in the page errors list

    • Errors rendered like this: [T24-000] street: INPUT MANDATORY FOR GIVEN SECTOR relate to Customer fields that we're not providing inputs for in this simple demo screen.

      These necessarily:

      • identify the fields in question via their internal field names (since this is all we know from the error details returned by the server)
      • are non clickable (since, for these, we have no screen field that we could highlight / navigate the user to).
  1. Though (currently) limited to the creation of a single entity type (an "onboarded" customer), the internal architecture of demo application aims to reduce the work involved in adding similar functionality for other entity types to an absolute minimum.

    In fact 85 percent (or more) of the implementation (at both the "web application" level and the "business web component level") is actually reusable (API entity type independent) "framework" code.

  2. At the outermost level, the application consists of a top-level page (index.html) that:

    • defines the following top-level elements:

      • the left-hand navigation (<uwc-navigation-rail> - one of the web components included in the unified-ux library)
      • a "glasspane" div (used to prevent the user from interacting with other parts of the screen during server interactions / while modal message boxes / dialogs are displayed)
      • various fixed position / centered "overlay" <div>s (for modal dialogs, message boxes, the welcome splash)
      • an (initially hidden) <iframe> to host the content for the selected top-level navigation option.

      NB: Web applications relying on large, monolithic component libraries can suffer from scaleability problems (slow page load times, excessive browser memory usage).

      A fringe benefit of the <iframe> approach is that it caters for the possibility of limiting the component library footprint of the web application as a whole (a) the set of components required by the outer page, plus (b) that required by the currently-loaded <iframe> content page.

      As you'll see, we have made our iframe content page "responsive" to resizing of the containing window/tab (vs. such actions merely causing unwanted scrollbars to appear).

    • implements (via inclusion of js/main-page.js) common "application level" aspects such as:

        • defining the top-level navigation items
        • defining the menu items for the navigation rail's "settings" icon
        • implementing / attaching callback functions implementing the actions for each of the above
        • checking for the presence of the API key cookie
        • validation of (possibly expired) API key cookie value,
        • managing the collection of (new) API key from the user (and subsequent validation / storage as cookie) when needed
      • Unsurprisingly, at the database level, an entity (such as a customer) not merely a collection of freeform text valus - it includes foreign-key references to other entities (e.g. sectors, countries) defined in the same database.

        For such fields, rather than offering a simple text field, our front-end needs allow the user to choose a valid value from a list (e.g. using the UUX <uwc-combobox> component), hence for each such field, we need to retrieve (and store) a list of display-text/key pairs.

        To this end, js/main-page.js:

        • coordinates the population of an (application-scoped) dynamic list registry (js/modules/dynamic-list-registry.js) with the labels / values (retrieved via multiple, concurrently-executed Transact API calls)

        • provides a "proxy function" (getListEntriesForListName(listName)) to facilitate the retrieval of list data from (the single instance of) that registry by <iframe> (all) content pages

        NB:

        • at the macro level, execLoadDynamicListDataRegistryFlow()) caters for the possibilityof failures of any/all of the API calls in this process, reporting any such errors to the user and offering an opportunity to retry the list-registry population process from the top

        • within js/modules/dynamic-list-registry.js, the details of each list to be retrieved, the API call to be used to retrieve it, the maximum time to wait for a response, any post-processing to be applied to the returned list data (e.g. doSortByLabel, doPrefixLabelsWithValues) are retrieved from a JSON data file: data/dynamic-list-specs.jsn (the "magic" that deals with the concurrent execution of the requests being Promise.allSettled() return at the bottom of fetchDynamicListDataFromServer())

        • at the next level down, the retrieval of both (a) the above JSON data file, and (b) the data for each list are delegated to js/modules/json-request-dispatcher.js methods (nonAPIGet() and apiGET(), respectively), meaning that we benefit from strongly-typed Error(s) (including ResponseBodyJSONSyntaxError, for example, from which pinpoint error messages can be derived - should the response entity provide to be unparsable as JSON)

        • showSystemAlertMessage(): displays a (formatted) alert message as a (centered) modal message box overlaying other page content

        • apiPOST(): layered on top of js\modules\json-request-dispatcher.js (see above), this manages the posting of manages the POSTing of a specified API entity object (e.g. Customer) to the specified API end-point, returning the entity object from the response on success, else interpreting the (strongly-typed) Error thrown by ([json-request-dispatcher.js] apiPOST()) into a user-friendly error message, reporting that to the user via showSystemAlertMessage() and returning null on failure.

          content/content.js (the generic helper library for <iframe> content pages such as content/onboard-customer/onboard-customer.html) uses this to provide manageAPIEntitySubmit(), which takes care of auxiliary aspects such as:

          • the building of the POST entity from the user-populated fields
          • interpretation of the server response (see js/classes/api-post-response-digest.js)
          • (on success) inclusion of name/value pairs for auto-generated field values in the success message
          • (error) interpretation of server-side validation error details into displayable "page error" items
  3. Communication/interactions between the outer page and the current inner <iframe> document are managed in 2 ways:

    • by firing custom events that are (or more acurrately, "may be "listened" for by the recipient (this mode of communication is used both from the outer page to the <iframe> content page and vice versa)

      An example of event-based communication in the inner-iframe-document-to-outer-page direction is the mechanism by which an <iframe> content page notifies the outer page it is fully loaded (and therefore ready to be interacted with) to the outer page (which is in charge of the "glasspane" used to prevent user interaction while the content page is loading). Briefly, this involves:

      • the <iframe> content page (e.g. content/onboard-customer/onboard-customer) firing a "content-page-ready" event (via content/content.js helper function: notifyContentPageReady()) on completion of its <body> tag's onload callback.
      • the main page (index.html / js/main-page.js) having registered its onContentPaneReady() as the window-level listener for "content-page-ready" events.

      An example of event-based communication in the opposite (i.e. outer-page-to-inner-iframe-document) direction is the handling of the Layout direction and Theme-switching options (found within the menu opened via the "gear" icon at the bottom of the navigation rail).

      Both of these actions necessarily involve updates both to (a) the outer page and (assuming the <iframe> is being displayed), (b) the content document within that <iframe>. The callbacks that implement these actions ([js/main-page.js] setLayoutDirection(layoutDirection) and setTheme(themeName)) both work in essentially the same way:

      • first, they update the main page by setting the relevant attribute (dir or theme, respectively) on the main page's <html> element to the applicable value.

        (This alone is sufficient to provoke the necessary visual update to the main page given (a) the CSS rules defined in main.css and (b) that layout-direction-sensitive UUX library components are (already) implemented to respond to the value of the dir attribute on the <html> element as a layoud-direction cue).

      • next, they dispatch a custom "look-and-feel-changed" event to the <iframe>'s content document.

      • assuming the content document is one that includes content/content.js, this will automatically have added its own own adoptLookAndFeelFromParentWindow() as the listener for "look-and-feel-changed" events on load, and this simply propagates the dir and theme attributes from the <html> element of the main page to the <html> element of the <iframe>'s document (which provokes the necessary visual update(s) within that scope)

    • Via window.parent <iframe> documents can also call any/all functions (e.g. apiPOST(), showSystemAlertMessage()) defined by the outer page and the scripts (e.g. js/main-page.js) that it includes.

  4. Dynamic web component dependencies injection

    In addition to being runnable from this website, for development purposes, our demo application also needs to be runnable locally (ideally in a change-aware web server such as es-dev-server) both:

    • by Temenos UUX developers
    • by external developers who have downloaded it / built it against our UUX nexus repository (as described below)

    The (runtime) source of the associated web component definitions (i.e. the demo-specific onboard-customer component, the core UUX components referenced by this, plus the core UUX <uwc-navigation-rail> component referenced by the outer page) is necessarily slightly different for each of the above contexts.

    In the website context, for example, those components are referenced from a single "rolled-up" library (lib/uux-scale-demo-components-umd.js) that we produce as part of the website build process.

    In the two "developer" contexts, however, we want es-dev-server to be able to pick up the javascript definitions of those components individually each time they are automatically recompiled as the developer saving changes to their typescript (.ts) source-file definitions.

    In order to avoid the need to maintain variant sources of index.html and content/onboard-customer/onboard-customer.html (each containing different hardcoded <script> tags to rope in the web components), these files instead include a reference to js/uux-dependencies-injector.js, which:

    • deduces the runtime context from:
      • the hostname and port of the (top-level) window's location

      • comparison of window vs. window.parent (to determine whether the script has been included by the top-level index.html page or a content page such as content/onboard-customer/onboard-customer.html, in which case relative hrefs will need to include a further ../..)

    • simply writes the applicable <script> and <link> tags into the document at the point in the <head> tag where js/uux-dependencies-injector.js was included.

  5. Generic <iframe> content page / web component infrastructure aspects

    In this initial incarnation of the demo application (which we are hoping to develop further), the API entity-related functionality is limited to the creation of new API entities (vs. retrieval / editing of existing ones). This is reflected in the associated content-page / component-level infrastructure, which (as things stand) only caters for those "cross API entity-type" concerns that emerge from that limited functional scope.

    A further limitation is the (unrealistically) limited provision for (repeatable) "multi-value" / "sub-value" field groups:

    • currently input fields are provided only for the first instance of such field groups (i.e. we're not currently providing the controls that, in a real-world application, a user would need in order to be able either (a) to add further instances or (b) remove existing ones)

    • currently the "multi-value" / "sub-value" field-group aspects are recognised / modelled only to the extent necessary:

      • to extract (correctly structured) POSTable entities from the subset of (component-generated) fields that the user has populated
      • to associate server-side validation errors with the correct instance of a multi-valued / sub-valued field (for the purpose of providing clickable page error items)

    To summarize: while existing infrastructure makes a reasonable fist of "commoning up" generic "cross API entity-type" aspects emerging from the limited functional scope of this demo, it leaves some significant gaps that would clearly need to be filled in order for this to constitute an adequate base for (more fully-featured) "real-world" applications.

    With that said, below are some high level some pointers as to how / where the generic (cross API entity-type) aspects that emerge - even in the context of this limited functional scope - are currently addressed.

    Feel free to download [sources] (and unpack to some convenient directory) for reference.

    (Should you wish to go a step further, you can find instructions on building / running those downloaded sources locally on your own machine here).

    For any API entity type ("Customer", "Account", ...), we need some way facilitate our API Entity web component's rendering the relevant input elements in a way that supports:

    • the building of the (JSON) payload of the API POST request to create the entity from whatever values the user has entered into the input fields of relevant (component-generated) entity-input screen

      In order to do this, we need to know (for each field):

      • the logical name of that field (as understood by the relevant "create-entity" API call)
      • whether we need to supply any value(s) for that field as an (unquoted) number (vs. a quoted string)
      • for fields that appear in "repeatable" field groups:
        • the name of the containing multi-value group (and which instance of that group any user-entered value relates to)
        • [for a sub-valued field] the name of the containing sub-value group (and which instance of that group - within which instance of its parent multi-value group - any given user-entered value relates to)
    • the relating of any internal field names/paths mentioned in the [server-side validation] error details to corresponding field elements within the (component-generated) entity-input screen (bearing in mind that, for multi-valued/sub-valued fields, we need to be able to find the input element within the correct instance of the containing repeatable field group)

    In outline, the approach taken involves:

    • Providing the means for an API entity component to create (and render()) appropriate field definitions (src/decorators/api-entity-component.ts, src/components/abstract-api-entity-component/abstract-api-entity-component.ts)
    • Provision of the means for javascript external to the component to extract a "live" model of an entity component's fields from the screen elements rendered from its field definitions ([src/decorators/api-entity-component.ts] getAPIEntityModel())
    • Provision of generic (application-framework vs. component level) code to navigate the "live" entity model extracted from a(ny) entity component for the purpose of:
      • generating the POSTable entity from the subset of user-populated fields within that model ([content/content.js] _mapAPIEntityModelToAPIEntityObject())
      • mapping field references encountered in server-side validation errors back to the input element (if any) for [the correct instance of] the referenced field ([content/content.js] manageAPIEntitySubmit())

    In slightly more detail (working from the outside in) we have:

    • content/onboard-customer/onboard.customer.html: this is the html page that includes the <uwc-onboard-customer> tag implemented by src/components/onboard-customer/onboard-customer.ts.

      It includes the following javascript libraries:

      • ../content.js: defines various generic application / API-entity-independent helper functions
      • ../../js/classes/api-post-response-digest.js: provides a logical (object model) view of an API POST response (used by ../content.js)
      • ./onboard-customer.js, which:
        • defines the init() method referenced as the onload handler for <body>; this:
          • initializes a reference (uwcOnboardCustomerElem) to the (src/components/onboard-customer/onboard-customer.ts) component instance
          • obtains a reference (customerEntityModel) to that component's "live" API entity model (for subsequent use in onEntitySubmit()'s calls to [../content.js] manageAPIEntitySubmit())
          • finds all the list-dependent (<uwc-combobox> input) elements within uwcOnboardCustomerElems shadowRoot, initializing the options property of each to point to the relevant array of list-item label/value pairs retrieved via parent.getListEntriesForListName(listName) (where listName is the logical name defined by element's listName attribute)
          • adds onEntitySubmit as the listener for any (custom) "entity-submit" events that may be dispatched by uwcOnboardCustomerElem (onclick of its "Submit" button)

        • defines the onboard-customer (component) -specific override of [../content.js extractReportableAutoGeneratedFieldDescriptionValuePairsArray() (responsible for extracting the onboard-customer-specific field/server-populated-value pairs for the API POST success message)

        • defines onEntitySubmit(). Added by init() as the listener for any (custom) "entity-submit" events fired by uwcOnboardCustomerElem, "Submit" button onclick, this first checks the supplied event to see whether the component detected any client-side validation errors (alerting the user if so), else (if not) invoking [../content.js] manageAPIEntitySubmit(), supplying the customerEntityModel obtained by init() as an argument.
    • src/components/onboard-customer/onboard-customer.ts: this is the (typescript) source definition of the web component that implements the <uwc-onboard-customer> tag that we saw in content/onboard-customer/onboard-customer.html

      Let's jump in at the component's (lit-element lifecycle) render() method and work outwards from there:

      • render(): At top-level, we see:

        • several <uwc-card> elements (corresponding to the field groups we saw on screen) being arranged within containing <uwc-grid> elements, followed by...
        • a <uwc-button> element implementing the component's "Submit" button

        Note that (unlike <uwc-onboard-customer>) <uwc-card>, <uwc-grid> and <uwc-button> are all standard ("core") UUX library components).

        Moving on to the content of the various <uwc-card> tags, we see that (rather than being defined directly "inline"), these are included into the result via:

        • multiple calls to this.renderSingleValuedField() for various SingleValuedFieldDefs.* values
        • a single call to this.renderMultiValueGroup() for multi-value group definition: MultiValueGroupDefs.COMMUNICATION_PREFS

        Those lower-level render*() methods are inherited from AbstractAPIEntityComponent as defined in src\components\abstract-api-entity-component\abstract-api-entity-component.ts. The "field definition" arguments being passed to them are defined by onboard-customer.ts as constants (organised into naming-scope container objects: SingleValuedFieldDefs, MultiValuedFieldDefs, SubValueFieldDefs), those within the latter containers being referenced subsequently as values for constants within the (higher-level) naming scope object:MultiValueGroupDefs.

        NB: MultiValueGroupDefs.RELATIONSHIP_DETAILS (which refers to SubValueGroupDefs.JOINT_RELATION) isn't currently referenced in the component's render() method. It was used to test the handling of sub-value groups during development, however, and (for the time being, ast least) is left "in situ" to illustrate provisions for that aspect.

    • Looking at the field (vs. group) definition constants within onboard-customer.ts, we can see:

      • that these are created via various static AbstractAPIEntityComponent methods having names of the form:

        create<fieldScope>API<basicFieldType>FieldDef

        ...where:

        • <fieldScope> is one of:

          • SingleValued
          • MultiValue
          • SubValue
        • <basicFieldType> is one of:

          • Text
          • List
          • Date
      • that all of these methods include parameters for:

        • apiFieldName: the (internal) name by which the field is known to the API services (both in outgoing POST messages, and in the error-details of incoming POST responses)

        • fieldLabel: the end-user-visible label/placeholder for the field

      • that other parameters (offered by some methods, but not all) include:

        • fieldComponentType: where there's a choice, identifies the type of UUX component that should be used to render this field, e.g:

          • for fields with a <basicFieldType> of List, this could be APIFieldComponentType.COMBOBOX or APIFieldComponentType.SELECT

          • for fields with a <basicFieldType> of Text, this could be APIFieldComponentType.TEXT_FIELD or APIFieldComponentType.TEXT_AREA
        • mandatory: whether or not the field is to be flagged as "mandatory" _(defaults to false where unspecified)

        • listName: relevant only for fields with a <basicFieldType> of List, this defines the internal name by which the the associated list is known (e.g. as defined by the listName attribute of the relevant entry in data\dynamic-list-specs.jsn)

        • listSelectionMode relevant only for fields with a <basicFieldType> of List and fieldComponentType of APIFieldComponentType.COMBOBOX, this effectively defines whether the field should allow multiple selection

      The main motivation for abstracting the idea of field definitions (and the means for creating / rendering them) into AbstractAPIEntityComponent was to provide a uniform way of rendering fields (and their containing groups/group instances) that would support the extraction of "live" entity models (currently by via the @apiEntityComponent (src\decorators\api-entity-component.ts) decorator method: getAPIEntityModel()).

      On the rendering side, this basically involves:

      • "annotating" field elements (using custom attributes and tagging CSS class-names)
      • rendering additional (similarly annotated) "container" elements for multi/sub-value groups and their instances.
  • src\decorators\api-entity-component.ts

    This (class-level) decorator works by extending the class (AbstractAPIEntityComponent-derived) class it's called upon to decorate to offer an additional getAPIEntityModel() method that returns an APIEntityModel object.

    Rather than being a single-use, point-in-time "snapshot", the returned APIEntityModel is actually "live" model whose query methods all work by executing querySelector() calls on the ("annotated") DOM of the decorated component's shadowRoot (meaning that the values returned methods all reflect the current values of such component-generated fields as are present at the time those methods are called).

    Those methods include:

    • model traversal methods: getSingleValuedFields(), getMultiValueGroups() (used by [content/content.js] mapAPIEntityModelToAPIEntityObject())

    • a (top-level) findField() method that takes an API field plus:

      • [for a multi-value/sub-value field] the API name / required instance index for the containing multi-value group
      • [for a sub-value field] the API name / required instance index of sub-value group (within the required multi-value instance) ...and returns an APIField object (providing methods such as: getElement(), getAPIEntityName(), getLabel(), getValue())

      (This method is used by used by [content/content.js] manageAPIEntitySubmit() to locate the APIField(s) referenced in error-details within entity POST responses from the server for the purpose of generating the clickable page error list).

    • assorted lower level "finder" (find*) methods for locating a named MultiValueGroup, a specific MultiValue instance, a SubValueGroup within a specified MultiValue instance, a SubValue instance within a SubValueGroup, etc.

    Within src/components/onboard-customer/onboard-customer.ts, we can see this (class-level) decorator being roped in as follows:

    @apiEntityComponent(NUMBER_TYPED_API_FIELDNAMES)
    export class OnboardCustomer extends AbstractAPIEntityComponent {
    ...
    }

    ...where NUMBER_TYPED_API_FIELDNAMES is an array containing the API names of those (customer) fields flagged (by the API) as having number-typed values (i.e. values must to be presented without enclosing double-quotes within the JSON entities for outgoing POST requests).

    Within the decorator code, this information is used by (APIField).getValue() to convert the source value (which will always be a String as stored by the input element) into a Number object (for return) where appropriate.

    Further downstream (i.e. at the point where the API entity object built by [content/content.js] mapAPIEntityModelToAPIEntityObject() eventually gets serialized into JSON for an outgoing POST request), this ensures that the values for such fields appear unquoted as expected/required by the API.

  1. NodeJS / NPM

    The Node-LTS exe downloadable from here will install (or upgrade an existing installation to) both of the above to the latest stable releases (npm 8.1.2 and 16.13.1 at the time of writing).

    If you have these installed already:

    • Check which versions you currently have installed by executing: npm --version and node --version

    • If these are significantly older than those identified above, we'd recommend upgrading (by downloading / running the installer) in order to prevent problems during the npm install step below.
  2. Yarn

    Once you have NPM installed (see above), you can check whether you have the Yarn Package Manager installed by executing:

    yarn --version.

    (Any version from 1.22.10 onwards should be fine).

    • To install yarn (for the first time), execute:

      npm install -g yarn

    • To upgrade an existing yarn installation to the latest version, execute:

      npm update -g yarn

Download the zip file (containing the demo-application-specific sources, a package.json and other supporting configuration files necessary to build / run the application locally) and unpack to a convenient directory on your machine.

In order to build demo sources, you will need to configure your npm so that it knows how to find the repository containing the Unified UX components, and the base64-encoded credentials for accessing that repository.

For a limited time, you may use our guest account, as described below.

For permanent access, however, you'll eventually need obtain a Temenos Customer Support Portal (TCSP) account, following which the process would differ from that outlined below only in that the value for the //repo.temenos.com/repository/npm-releases/:_auth property would need to the base64-encoded form of your TCSP username:password string (which you can easily generate online at www.base64encode.org) vs that for our guest account.

Create (or edit) a file called .npmrc file in your user home directory (e.g. C:\Users\jdoe on windows, or ~ if you're on a unix-flavoured OS) to include the following property definitions:

@unified-ux:registry=https://repo.temenos.com/repository/npm-releases/
strict-ssl=false
# All other packages come from the public NPM registry:
registry=https://registry.npmjs.org/
always-auth=false
//repo.temenos.com/repository/npm-releases/:_auth="dXV4LWNvbnN1bWVyOmJpZ2JhZHdvbGY="
//repo.temenos.com/repository/npm-releases/:always-auth=true

Open a command / shell window on the directory where you unpacked the zip download, then execute the following commands:

  1. npm install
  2. yarn build

To run the application application in a change-aware web server (es-dev-server), execute:

yarn start