Components
This guide assumes that you are already familiar with concepts inherent in JSF programming and in Ivy development.
This document provides a high-level explanation of how to develop a Portal widget. The ability to use Portal services and styles can be particularly useful to developers who wish to do one or more of the following:
-
Create their own widgets for Portal which have a consistent look and feel with the existing widgets.
-
Reuse existing portal services to create their own widgets which can manipulate Portal data, such as: cases, tasks, process starts, users,...
This section introduces the Html Dialog Component and Portal services, predefined styles used in building a widget, and goes on to describe the process of designing and implementing.
Portal widgets should be implemented using the Html Dialog Component technology from Axon Ivy and follow the famous model-view-controller pattern.
Furthermore, to have a clean architecture and avoid a lot of headaches going forward, we suggest that you should separate your widget into layers like below:
-
Entities
Entities are the business objects of the widget. They encapsulate the most general and high-level rules. They are the least likely to change when something external changes. (e.g.: by a change to page navigation, or security).
-
Use Cases
Use case are widget specific business rules. This layer encapsulates and implements all of the use case of the widget. Changes in this layer should not affect the entities. This layer should not be affected by changes to externalities such as the Portal services, the UI, or any of the common frameworks.
-
Interfaces Adapters
Interfaces Adapters are set of adapters that convert data from the format most convenient for the use cases and entities, to the format most convenient for some external agency such as the database or the web. Similarly, data is converted, in this layer, from the form most convenient for entities and use case, into the form most convenient for whatever persistence framework is being used. (The presenters, views, and controllers all belong in here. The models are likely just data structures that are passed from the controllers to the use case, and then back from the use cases to the presenters and views.)
-
Frameworks and Drivers
This layer is generally composed of frameworks and tools such as the database, the web framework, Portal services, etc. This layer is where all the details go. The Web is a detail. The Portal services are detail. We keep these thing on the outside where they can do little harm.
Tip
There's no rule that says you must always have just the four layers above. However, you should always apply that the source code dependencies point from mechanisms to policies:
Frameworks and Drivers > Interfaces Adapters > User Cases > Entities
By doing so, you will create a widget that is intrinsically testable, independent of frameworks, independent of UI, independent of database, and independent of any external agency. When any of the external parts of the system become obsolete, like the database, or the web framework, you can replace those obsolete elements with a minimum of fuss.
You should have an understanding of the following technology and concept as you build your widget:
-
Managed Beans: in Html Dialog Component it is possible to communicate with normal Java Objects by using Managed Beans.
-
User Dialog Concept: an Html Dialog Component follows the model-view-controller pattern of the User Dialog Concept.
-
Model is a data class whose data fields can be bound to widget properties of the view via the special object data.
-
Controller is implemented by a series of UI processes that can be mapped to events on the view such as mouse clicks. Axon Ivy provides the keyword logic to call an event process or a method process in the logic.
-
View of an Html Dialog is defined with the means of an XHTML document.
-
There are separate services for working with each type of data:
-
Application Services: set of services for getting information about applications.
-
Absence Services: set of services for manipulating the user's absence.
-
Case Services: set of services for working with cases and related data, such as: additional properties, notes,...
-
Task Services: set of services for working with tasks.
-
Process Start Services: set of services for querying process starts from the Portal system.
-
Security Services: set of services for querying users and roles.
-
User Setting Services: set of services for manipulating the user settings and related data, such as: email settings, language settings.
-
Portal Configuration Services: set of services for controlling the Portal configuration.
Portal comes with some useful widgets:
-
Task widget
Below is the sample how the task widget being use in the default template:
<ui:define name="taskWidget">
<ic:ch.ivy.addon.portalkit.component.TaskWidget id="task-widget" tasks="#{logic.getTasksOfSessionUser()}" ... />
</ui:define>
-
Process widget
Below is the sample how the process widget being use in the default template:
<ui:define name="processWidget">
<ic:ch.ivy.addon.portalkit.component.ProcessWidget id="process-widget" compactMode="true" ... .>
</ui:define>
-
Statistic widget
Below is the sample how the statistic widget being use in the default template:
<ui:define name="statisticWidget">
<ic:ch.ivy.addon.portalkit.component.StatisticWidget id="statistics-widget" compactMode="true" ... >
...
</ic:ch.ivy.addon.portalkit.component.StatisticWidget>
</ui:define>
Portal setup these widget with the default settings for you, but you can always re-define them in order to match with your needs. Moreover, if you want to turn off a built-in widget, you can simply leave its ui:define container empty like this:
<ui:define name="taskWidget">
<!-- leave it empty -->
</ui:define>
There are separate common styles are predefined to ensure every Portal widget has a consistent structure and appearance:
<div class="widget">
<div class="widget-header">
<ul class="widget-header-menu">
<li class="widget-header-menu-item">...</li>
<li class="widget-header-menu-item">...</li>
<li class="widget-header-menu-item">...</li>
...
</ul>
...
</div>
<div class="widget-content">
<div class="widget-content-list">
<div class="widget-content-list-item">...</div>
<div class="widget-content-list-item">...</div>
<div class="widget-content-list-item">...</div>
...
</div>
</div>
<div class="widdget-footer">
...
</div>
</div>
The general flow for developing a widget for portal is as follows:
-
Design your widget, deciding which parts to implement in Ivy component, and which parts to implement as pure JSF.
-
Create an Html Dialog Component.
The following code fragment defines an example Html Dialog component:
<cc:interface componentType="IvyComponent">
<cc:attribute name="caption" />
</cc:interface>
<cc:implementation>
...
</cc:implementation>
A component could be inserted with the ic tag.
<ic:my.namespace.ComponentName ... />
For more information, see the Html Dialog Component section in Axon Ivy Designer - Help: Designer Guide > User Interface > User Dialogs > Html Dialogs
- If you are writing a widget, which manipulates task, case,... consider using Portal built-in services.
-
Optionally, your widgets can have their own configuration. There are separate methods for manipulating widget configuration:
-
You can initiate or update your widget configuration by passing an JSON object to
saveSettings()
. -
You can load your widget configuration by calling
loadSettings()
.
-
The general flow for integrating a widget into Portal homepage is as follows:
-
Create a new home page which uses the
DefaultHomePageTemplate.xhtml
template. By doing this, your new home page will inherit the widget from the previous home page and has a place holder for your own widgets. Your custom home page should look like below:<ui:composition template="/layouts/DefaultHomePageTemplate.xhtml" xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://xmlns.jcp.org/jsf/core" xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets" xmlns:ic="http://ivyteam.ch/jsf/component">
<ui:define name="customWidget">
...
</ui:define>
</ui:composition>
-
Create a new process start for the new home page. Now you will use this process start as the entry point of your portal instead of the default one. To let portal know about your new portal home, you have to go to the portal settings and set the portal home url to the new one.
-
In your new home page, place your widget inside the customWidget section.
<ui:define name="customWidget">
<ic:my.namespace.ComponentName ... />
...
</ui:define>
For more details, visit Portal home.
Portal separates exception into 2 types: ajax and non-ajax exception.
Portal handle non-ajax exception for you. You do not need to do anything for this type of exception.
Portal also handle ajax exception for you as default, but you can implement your own exception handler by using the Primefaces built-in exception handler: p:ajaxExceptionHandler
.
Your Portal Project is dependent on PortalTemplate project, in which there are 7 templates that can be used directly.
-
Basic template
-
Two column template
-
Task template
-
Case template
-
Task list template
-
Case list template
-
Default homepage template
These templates have the same header, which is a menu of applications that you configure in Administration page. Since version 6.4, Portal officially supports responsiveness for 3 resolutions: iMac (1920*1050), iPad (1366*1024) iPad Portrait: (1024*1366), every templates has its default responsiveness, you can refer to Responsiveness to override it. Besides, there are user settings like: Absences, Email, Language Settings and Administration (for admin only). Details about user settings can be found in Settings.

Basic template provides basic layout where user can put their custom content. It lacks Portal menu and Case details. We recommend to use task template for your process.
-
Create a new HTML User Dialog and then use
ui:composition
to define the template inside and reuse the default responsiveness behavior. To override it, please usepageContent
instead ofsimplePageContent
and Responsiveness.<ui:composition template="/layouts/BasicTemplate.xhtml">
<ui:define name="pageTitle">Sample Page</ui:define>
<ui:define name="simplePageContent">
This is sample content.
</ui:define>
</ui:composition>
-
See the result after using Basic template for example:
Two column template inherits Basic Template. It has 2 columns which user can customize their contents. Normally, the first column is for navigation, the second for displaying corresponding content.
-
Create a HTML User Dialog, define template in
ui:composition
and insert content of second column and third column usingui:define
.<ui:composition template="/layouts/TwoColumnTemplate.xhtml">
<ui:define name="pageTitle">Sample Page</ui:define>
<ui:define name="navigationRegion">
Navigation Region
</ui:define>
<ui:define name="contentRegion">
Content Region
</ui:define>
</ui:composition>
-
See the result after using Two column template for example:
Task template is used for displaying task functionality and related information to support completing the task. There are a lot of regions to be filled with your custom content:
-
Request name
-
Process chain
-
Errors
-
Information
-
Dynamic tabs
-
Request form
-
Case information tab
-
Buttons at footer
-
Create a new HTML User Dialog and then use
ui:composition
to define template which you use inside.<ui:composition template="/layouts/TaskTemplate.xhtml">
-
Set
task
value so that thetaskName
is available to users where they can see the task name of request. It is mandatory.<ui:param name="task" value="#{ivy.task}" />
-
Set
caseId
value so that theCase information tab
is available to users where they can see info of case, documents, related tasks and history. It is mandatory.<ui:param name="caseId" value="#{ivy.case.id}" />
-
Set data to
actualStepIndex
andsteps
variables which are used for ProcessChain component in template. It is mandatory.<ui:param name="actualStepIndex" value="#{data.actualStepIndex}" />
<ui:param name="steps" value="#{data.steps}" />
-
Set data to
processChainDirection
variable to set direction for for ProcessChain component in template. There are two values: "HORIZONTAL" and "VERTICAL". Direction of ProcessChain component is "HORIZONTAL" by default.<ui:param name="processChainDirection" value="VERTICAL" />
-
Set data to
processChainShape
variable to set shape for for ProcessChain component in template. There are two values: "CIRCLE" and "LINE". Shape of ProcessChain component is "CIRCLE" by default.<ui:param name="processChainShape" value="LINE" />
-
Inserts contents for
taskName
,errorsZone
,infoZone
. It is optional.<ui:define name="taskName">...</ui:define>
<ui:define name="errorsZone">...</ui:define>
<ui:define name="infoZone">...</ui:define>
-
Inserts some new tabs, refers some segment of code as below. If your application has multiple tabs, use it and turn off request form by set
showTaskFormTab
to false.<ui:param name="showTaskFormTab" value="false" />
<ui:define name="dynamicTabs">
<p:tab title="My first tab">
<p:inputText id="first-name" value="#{data.firstname}"/>
</p:tab>
<p:tab title="My second tab">
<p:inputText id="last-name" value="#{data.lastname}"/>
</p:tab>
</ui:define>
-
Overwrite contents of default tab. Use it when your application need only 1 tab.
<ui:define name="taskForm">
<h:form>
<p:outputLabel name="myCustomLabel" />
...
</h:form>
</ui:define>
-
Set visible/invisible for default tab case information. Set following variables as
true
if you want to visible and vice versa.<ui:param name="showCaseStatusInfoTab" value="true" />
-
Inserts left buttons and right buttons which stay at the bottom of the page. It is optional. You can use it to define your action button. Consider using
partialSubmit
to submit your data im tabs.<ui:define name="leftButtons">
<p:commandButton value="Save" actionListener="#{logic.save}" partialSubmit="true" process="first-name last-name" update="first-name last-name" />
</ui:define>
<ui:define name="rightButtons">
<p:commandButton value="Cancel" actionListener="#{logic.cancel}" immediate="true" />
</ui:define>
Case template is similar to Task Template in both UI and usage. The difference is it is used for displaying case details functionality.
Default homepage template is used to create pages that have the look as default homepage of Portal. Besides, users can customize it by disabling default widgets, add new widgets, change position of widgets. For more details including basic and advanced customization, refer to Portal home
Task list template is used to display task list where user can see tasks and their details.

-
Create a new HTML User Dialog and then use
ui:composition
to define template.<ui:composition template="/layouts/PortalTasksTemplate.xhtml">
</ui:composition>
-
Data class of this dialog should have an attribute named
taskView
with typech.ivy.addon.portal.generic.view.TaskView
. By changing this attribute, user can modify title of the task list widget, collected tasks (throughdataModel
) and more. The following is a sample to build a taskView.import ch.ivy.addon.portalkit.datamodel.TaskLazyDataModel;
import ch.ivy.addon.portalkit.bo.MainMenuNode;
import ch.ivy.addon.portal.generic.view.TaskView;
TaskLazyDataModel dataModel = new TaskLazyDataModel();
dataModel.setIgnoreInvolvedUser(true);
dataModel.setSortType(ch.ivy.addon.portalkit.enums.SortType.BY_PRIORITY);
MainMenuNode category = new MainMenuNode();
category.value = "My Task List";
out.taskView = TaskView.create().dataModel(dataModel).pageTitle("My Task List").hideTaskFilter(true).category(category)
.showHeaderToolbar(false).createNewTaskView();
Case list template is used to display case list where user can see cases and their details.

-
Create a new HTML User Dialog and then use
ui:composition
to define template.<ui:composition template="/layouts/PortalCasesTemplate.xhtml">
</ui:composition>
-
Data class of this dialog should have an attribute named
caseView
with typech.ivy.addon.portal.generic.view.CaseView
. By changing this attribute, user can modify title of the case list widget, collected cases (throughdataModel
) and more. The following is an example to build a caseView.import ch.ivy.addon.portalkit.datamodel.CaseLazyDataModel;
import ch.ivy.addon.portal.generic.view.CaseView;
CaseLazyDataModel dataModel = new CaseLazyDataModel();
out.caseView = CaseView.create().dataModel(dataModel).withTitle("My Cases").buildNewView();
All templates require login to access by default. But templates also provide functionality to access page without login by adding the isNotRequiredLogin
parameter.
-
Create a new HTML User Dialog and then use
ui:param
to define the template inside<ui:composition template="/layouts/BasicTemplate.xhtml">
<ui:param name="isNotRequiredLogin" value="#{data.isNotRequiredLogin}" />
<ui:define name="pageContent">
This is sample content.
</ui:define>
</ui:composition>
-
Result after using template for example (All user settings and application menus will not visible).
Since version 6.4, Portal officially supports responsiveness for 3 screen widths: iMac(width 1920), iPad landscape(width 1366) and iPad portrait(width 1024).
To apply your styles for the above resolutions, you can add your own media query css:
/* Small screen */
@media screen and (max-width: 1365px) {/*.....*/}
/* Medium screen */
@media screen and (min-width: 1366px) and (max-width: 1919px) {/*.....*/},
/* Large screen */
@media screen and (min-width: 1920px) {/*......*/}
In Portal's new design, the main container's width should be changed according to menu state (expand/colapse).
To adapt the change, you need to initialize the ResponsiveToolkit
Javascript object and introduce 3 objects to handle 3 screen resolutions and each object has to implement the updateMainContainer
method.
Portal templates define their own responsiveness, you can redefine the footer section to override:
E.g. Initialize ResponsiveToolkit
for TaskList page.
<ui:define name="footer">
<script type="text/javascript">
$(function(){
var taskListLargeScreen = new TaskListLargeScreenHandler();
var taskListMediumScreen = new TaskListMediumScreenHandler();
var taskListSmallScreen = new TaskListSmallScreenHandler();
var responsiveToolkit = ResponsiveToolkit(taskListLargeScreen, taskListMediumScreen, taskListSmallScreen);
Portal.init(responsiveToolkit);
});
</script>
</ui:define>
Chat feature was implemented on Portal.
There are couple of reason, it's intentionally disabled by default:
-
Customers have their own Chat, they do not need another.
-
For using Chat, system administrator has to configure it on their server (needs additional Libraries).
-
With added libraries for using Chat, it slows AxonIvyEngine down.
-
It has log-in issue as if AxonIvyEngine is configured with IIS (version
7.5
or older) to manage SSO. -
Not fully support
UNICODE
characters on Ivy6.3
and upwards.
Follow the steps below:
-
First, IvyEngine/Designer needs some configuration to use Chat. Copy two libraries and then paste into
webapps/ivy/WEB-INF/lib
folder located onAxonIvyEngine, AxonIvyDesigner.
Note
You can find these libraries inside PortalKit module, located onPortalKit/lib_chat
or download from this site. -
Second, Enables Chat on UI by setting
enablesChat
param<ui:param name="enablesChat" value="true" />
Added this line to your pages that are using BasicTemplates of Portal (adds to
DefaultPortalHomeTemplate.xhtml
,TaskTempate.xhtml
, etc.)E.g.:
<ui:composition template="/layouts/BasicTemplate.xhtml">
<ui:param name="enablesChat" value="true" />
<...>
</ui:composition>
Or simply change param's value on
BasicTemplate.xhtml
<ui:param name="enablesChat" value="
#{enablesChat}
" /> to <ui:param name="enablesChat" value="true
" /> - Restarts AxonIvy Desinger/Engine. Then enjoy Chat.
In this section, we introduce 2 kinds of errors, when and how to handle them in Portal.
-
Ajax error : this kind of errors occur during a JSF ajax requests, for example when the user clicks on the show full mode button to tell the task widget switches to full mode, without handling the end user would not get any form of feedback if the action was successfully performed or not.
-
Non-ajax error : this kind of errors occur when user access to Portal from a url which could not be handled successfully by server side, or being navigated by a corrupted url. For example, when the user clicks on a link to start a task which does not exist.
By default, Portal handles all exceptions from ajax requests.
When an exception occurs, Portal will show an error notification with the exception type and message to end user. The exception details is available when user click on show details button.
Stacktrace on error messages can be showed/hid depend on ivy system property Errors.ShowDetailsToEndUser
.
Note
This feature is only available if using the portal default template:BasicTemplate
or its extension.
By default, when the server has any error such as : HTTP 404
, HTTP 500
, or exception while page's loading, AxonIvyEngine will show an default error page. E.g.:

You can find content of this page is the file located on ${AxonIvyEngineFolder}/webapp/ivy/ivy-error-page.xhtml
, but the error page is not user friendly, too much technical information that normal user may not understand. Thus, Axon Ivy Portal provides an alternative solution to make this page nicer.
Download the zip file below to configure on your own engine (or designer).
Important
Read README.txtBy default, users cannot use export feature of Portal. For using it, follow the steps below:
-
First, IvyEngine/Designer needs some configuration to use export. Copy library below and then paste into
webapps/ivy/WEB-INF/lib
folder located onAxonIvyEngine, AxonIvyDesigner.
Note
You can find this library insideAxonIvyDesigner
folder, underconfiguration/org.eclipse.osgi
(please search the library in this directory), or download from this site. - Restart AxonIvy Designer/Engine. Then use export function normally.
This component is a lazy loading list which displays all business cases of a business entity in your application. You can include this component everywhere:
In a page

In a dialog

First you need to link the cases to the business entity. Call the subprocess
SetBusinessEntityId
in the process which need to be linked
and input an identifier unique to your business entity. The subprocess will
set the id to the additional property "CASE_BUSINESS_ENTITY_PROPERTY" of the business case.

Include the process history component into your page:
<ic:ch.ivy.addon.portal.component.ProcessHistory businessEntityId="resourceA247" >
The value of the attribute
businessEntityId
must match the id input into the subprocess in the first step.
By default the component will load 20 cases at a
time. You can change this by setting the attribute
chunkSize
to the number you want
. You should use this attribute alongside with the attribute
scrollHeight
to configure the scroll bar of the list.
Note
If you use this component in a dialog, you must run this scriptprocessHistory.setup();
when the dialog is shown. For example:
<p:dialog widgetVar="process-history-dialog" id="process-history-dialog" width="800" height="500"
header="Process history of Resource A247" onShow="processHistory.setup();">
<ic:ch.ivy.addon.portal.component.ProcessHistory businessEntityId="resourceA247"
chunkSize="6"
scrollHeight="400" />
</p:dialog>
Important
If your process has a Trigger component or sends a signal to start another process with the option "Attach to Business Case that triggered this process" selected, the current case of the process will become a technical case and will not be loaded into the process history list. In this case You need to call theSetBusinessEntityId
subprocess
after the first Trigger or signal sending step.
Process Chain component of Portal provides features for users to know status of all steps in a process: the step's working, these steps are done, these steps is not done. These features are:
-
Support to display all working steps or display only helpful steps as begin, last, current, previous current, next current steps.
-
Support to change the shape of process chain: circle or line.
-
Support to change direction of process chain: horizontal or vertical.

Process Chain component can be integrated in any widget by including this component into a page. In order to use this component in a page, include this component to this page with following code:
<ic:ch.ivy.addon.portalkit.singleapp.process.ProcessChain id="process-chain-circle-horizontal"
componentId="component-circle-horizontal" shape="CIRCLE" direction="HORIZONTAL"
isShowAllSteps="FALSE" actualStepIndex="#{data.actualCurrentIndex}" steps="#{data.steps}" />
-
Must to set value for
actualStepIndex
parameter. This is current step index. -
Must to set value for
steps
parameter. This is list of working steps. -
Can change
shape
parameter toCIRCLE
orLINE
based on the requirement. Default value of this isCIRCLE
. -
Can change
direction
parameter toHORIZONTAL
orVERTICAL
based on the requirement. Default value of this isHORIZONTAL
. -
Can change
isShowAllSteps
parameter toTRUE
orFALSE
based on the requirement. Default value of this isFALSE
.
This component is a global growl introduced in BasicTemplate, you can use it to display your messages in Portal.

To make growl message appears as default after a task is finished, administrator could set the DISPLAY_MESSAGE_AFTER_FINISH_TASK
Portal variable to true.

If DISPLAY_MESSAGE_AFTER_FINISH_TASK
Portal variable is true, growl message will be displayed after a task is left.

After that, for each task, you can turn it off or override it. Firstly, when you submit form to interact task, you need to put
the
overridePortalGrowl
key to flash object with any value
Flash flash = FacesContext.getCurrentInstance().getExternalContext().getFlash(); flash.put("overridePortalGrowl", true); flash.setRedirect(true);
It's enough if you want to turn it off. To override the message, add
facesMessage
to this component
import javax.faces.context.Flash; import javax.faces.context.FacesContext; import javax.faces.application.FacesMessage; FacesMessage message = new FacesMessage("Task is done successfully"); FacesContext.getCurrentInstance().addMessage("portal-global-growl-message", message); Flash flash = FacesContext.getCurrentInstance().getExternalContext().getFlash(); flash.put("overridePortalGrowl", true); flash.setRedirect(true); flash.setKeepMessages(true);
Please refer to GlobalGrowl dialog in PortalExamples project for more details.
By default, the last drilldown level of a expiry chart is HOUR. It means that, to open a related tasks list of this chart, users must navigate from YEAR -> MONTH -> WEEK -> DAY -> HOUR, clicking on a column of HOUR chart to open the tasks.
To change this last drilldown level, users can set the value of EXPIRY_CHART_LAST_DRILLDOWN_LEVEL
in Global settings
.
For example, to navigate to task list immediately when clicking on a week column, set EXPIRY_CHART_LAST_DRILLDOWN_LEVEL = WEEK
:
