This document covers the best practices and design guidelines for ensuring good UI performance for xCP applications. It covers various areas like page design, server interaction, environment, etc.
|Change date||Description of change|
Best Practices / Guidelines
- Always try to be on latest patch level of xCP. Performance fixes are done in the product on an ongoing basis (as and when found).
- Try to use better browser, if it is allowed in the user environment. Preferred browsers (in descending order of preference): Chrome, Firefox/Safari, IE11, IE10, IE9. Avoid IE if possible, and if it is mandated to be used, then try to upgrade to IE11. Lower versions are really bad at rendering/JS performance. xCP 2.3 supports MS Edge on Windows 10 now. Use that if possible. It is extremely fast compared to IE.
Structure of the Page
- Avoid having large number of widgets on a single page. It impacts rendering performance as well as usability. Simple form widgets like text input, date time input, etc. will not have as much rendering impact compared to complex widgets like Results List, Content Tree, etc. Normally, whenever we've seen slow performing pages, there has always been large number of widgets on the page.
- Break up the page into multiple pages, if possible, to reduce the page size.
- If large number of widgets must be placed on the page, then try not to render all at once. You could use Tab Group widget to group such widgets into multiple tabs. This ensures that the widgets do not get rendered till user clicks on that specific tab. Please note that if "Render all tabs on load" configuration is checked for Tab Group, then you'll not get this performance improvement. Please refer to note below for details on why this configuration is available in Designer.
- Use Page Fragment widget to lazily load some portions of UI. For example, some portion could be loaded and displayed only when user performs some action like a button click. This ensures that the number of DOM elements on the page are less when page loads for the first time, and new elements are loaded only when required. Please note that Page Fragment has its own overhead of making a server call, but it should be light-weight call.
- Avoid having too many container widgets like Column Box, Border Layout, etc. If possible, try to achieve the required page design with lesser number of containers.
- Avoid having too many event subscriptions on the widgets. Event subscriptions get evaluated whenever corresponding events get fired, so if subscription is for some prolific event, then it might cause lot of expression evaluations, impacting the performance. You should also remember that there are implicit subscriptions when you directly type some expression in fields like "Value".
- If there is a Viewer widget on the page, then if possible try not to render it on page load. For example, you could move it to some tab inside a Tab Group, or load it only on some user action.
- If there is a Fragment widget on the page, and it needs the same model data as that of the page, then pass the current page model to Fragment's "model" input parameter, instead of passing "id" parameter. If you use "id" parameter, then the fragment will fire server call to load the data for that object id, when fragment is loaded.
- If you are using "HTML" data type in Value Display widget to render some HTML, and if such HTML includes <img> tags, then it might impact UI performance. In xCP 2,3, there is a checkbox named "Disable relayout of images inside HTML" introduced for Value Display configuration. Check this checkbox, and make sure that you provide "height" and "width" attributes for all <img> tags in the HTML.
- If you need to show or hide a group of widgets based on some condition, it is better to put all such widgets in a single container like Column Box, and then configure the same to be hidden or shown based on that condition, instead of configuring each widget separately.
Data Services Configuration
- Avoid having large number of data services (Interactions) on a single page.
- Execute data service only when required. It is far too common that "On Page Load" or "When input value changes" check-boxes are checked for a data service, even though it is not required to be loaded on page load, or has to be executed only when some user action occurs.
- In case some data service has to be executed inside a fragment on load, then either check the "On Page Load" checkbox, or subscribe to "On Fragment Load" event. Do not subscribe to "On Page Load" event.
- If possible, try to fetch data from server using lesser number of data services. You might want to merge multiple data services into one to achieve this. Number of server calls will impact the UI performance, especially when there is high network latency or there are large number of calls being made from UI.
- If some data service is used to fetch static data, then try to cache it in UI. This feature has been introduced in xCP 2.3. For earlier versions, see if Picklist can be used instead of data service.
- If there are Results List widgets on page which are not so important to be loaded on page load, then don't fire corresponding data service on Page Load, and instead fire it when required (e.g. user clicks on a "Refresh" button).
NOTE on Tab Group Configuration:
Tab Group widget has a configuration "Render all tabs on load". This was introduced earlier to solve a functional issue: By default, Tab Group will not render the content of the tabs which are not yet opened. This internally was causing the widgets inside those tabs to be not initialized. So if there was let's say a "Create" or "Update" or some other data service which takes inputs from various widgets across all tabs, then the value for widgets which are not yet rendered will come as blank, even if those widgets had initial value specified. If "Render all tabs on load" is checked, then it ensures that on page load, it renders widgets inside tabs other than first one too. And so widgets get initialized, and data service will get inputs correctly populated.
But starting with xCP 2.2 Patch 13 and xCP 2.3 GA, this configuration has become redundant. Even if widgets are not rendered, UI will ensure that internally the widget objects have the values populated and data service will get the inputs. Thus, it is recommended to never check "Render all tabs on load" checkbox.