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)*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.
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.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).
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 ouronboard-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
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).
Onboarding our first Customer
Close the modal message box, then:
Choose a value (e.g. Admiral) for the Title
<uwc-combobox>
fieldTIP: 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 itNow enter something plausible for the First Name and Last Name fields (e.g.
Fred
andSmith
)TIP: You can use
<TAB>
and<SHIFT+TAB>
to move forward / backwards to the next / previous field, respectivelyMove 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 pickGreat 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 fieldNotice 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"
indata/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
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).
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.
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).
- the left-hand navigation (
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 topwithin
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 beingPromise.allSettled()
return at the bottom offetchDynamicListDataFromServer()
)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()
andapiGET()
, respectively), meaning that we benefit from strongly-typed Error(s) (includingResponseBodyJSONSyntaxError
, 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 contentapiPOST()
: layered on top ofjs\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 viashowSystemAlertMessage()
and returningnull
on failure.content/content.js
(the generic helper library for<iframe>
content pages such ascontent/onboard-customer/onboard-customer.html
) uses this to providemanageAPIEntitySubmit()
, 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
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 (viacontent/content.js
helper function:notifyContentPageReady()
) on completion of its<body>
tag'sonload
callback. - the main page (
index.html
/js/main-page.js
) having registered itsonContentPaneReady()
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)
andsetTheme(themeName)
) both work in essentially the same way:first, they update the main page by setting the relevant attribute (
dir
ortheme
, 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 thedir
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 ownadoptLookAndFeelFromParentWindow()
as the listener for "look-and-feel-changed" events on load, and this simply propagates thedir
andtheme
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)
- the
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.
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
andcontent/onboard-customer/onboard-customer.html
(each containing different hardcoded<script>
tags to rope in the web components), these files instead include a reference tojs/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-levelindex.html
page or a content page such ascontent/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 wherejs/uux-dependencies-injector.js
was included.
Generic
<iframe>
content page / web component infrastructure aspectsIn 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()
)
- generating the POSTable entity from the subset of user-populated fields within that model (
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 bysrc/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 theonload
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 inonEntitySubmit()
's calls to [../content.js]manageAPIEntitySubmit()
) - finds all the list-dependent (
<uwc-combobox>
input) elements withinuwcOnboardCustomerElem
sshadowRoot
, initializing theoptions
property of each to point to the relevant array of list-item label/value pairs retrieved viaparent.getListEntriesForListName(listName)
(wherelistName
is the logical name defined by element'slistName
attribute) - adds
onEntitySubmit
as the listener for any (custom) "entity-submit" events that may be dispatched byuwcOnboardCustomerElem
(onclick of its "Submit" button)
- initializes a reference (
- 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 byinit()
as the listener for any (custom) "entity-submit" events fired byuwcOnboardCustomerElem
, "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 thecustomerEntityModel
obtained byinit()
as an argument.
- defines the
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 incontent/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 variousSingleValuedFieldDefs.*
values - a single call to
this.renderMultiValueGroup()
for multi-value group definition:MultiValueGroupDefs.COMMUNICATION_PREFS
Those lower-level
render*()
methods are inherited fromAbstractAPIEntityComponent
as defined insrc\components\abstract-api-entity-component\abstract-api-entity-component.ts
. The "field definition" arguments being passed to them are defined byonboard-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 toSubValueGroupDefs.JOINT_RELATION
) isn't currently referenced in the component'srender()
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.- several
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>
ofList
, this could beAPIFieldComponentType.COMBOBOX
orAPIFieldComponentType.SELECT
- for fields with a
<basicFieldType>
ofText
, this could beAPIFieldComponentType.TEXT_FIELD
orAPIFieldComponentType.TEXT_AREA
- for fields with a
mandatory
: whether or not the field is to be flagged as "mandatory" _(defaults tofalse
where unspecified)listName
: relevant only for fields with a<basicFieldType>
ofList
, this defines the internal name by which the the associated list is known (e.g. as defined by thelistName
attribute of the relevant entry indata\dynamic-list-specs.jsn
)listSelectionMode
relevant only for fields with a<basicFieldType>
ofList
andfieldComponentType
ofAPIFieldComponentType.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 additionalgetAPIEntityModel()
method that returns anAPIEntityModel
object.Rather than being a single-use, point-in-time "snapshot", the returned
APIEntityModel
is actually "live" model whose query methods all work by executingquerySelector()
calls on the ("annotated") DOM of the decorated component'sshadowRoot
(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 theAPIField
(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 namedMultiValueGroup
, a specificMultiValue
instance, aSubValueGroup
within a specifiedMultiValue
instance, aSubValue
instance within aSubValueGroup
, 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 aNumber
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.
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
andnode --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.
- Check which versions you currently have installed by executing:
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 TCSPusername: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:
Open a command / shell window on the directory where you unpacked the zip download, then execute the following commands:
npm install
yarn build
To run the application application in a change-aware web server (es-dev-server), execute:
yarn start