Karma Form Controls
k5-repeat-section
since v2.8.21
- Option
removeLabelto hide the remove button
{
"type": "k5-repeat-section",
"templateOptions": {
"removeLabel": false
}
}
k5-collapse
since v2.8.21
- renaming template option
uncollapsedTexttoexpandedText - adding template options
collapsedIconClassandexpandedIconClass(using font-awesome classes, see defaults in example)
{
"type": "k5-collapse",
"templateOptions": {
"collapsedText": "",
"expandedText": "",
"collapsedIconClass": "fa-square-o",
"expandedIconClass": "fa-check-square-o"
}
}
k5-select
since v2.8.18
- new
matchExpressionoption to override rendering of selected items - new dal
asyncproperty to allow async/typeahead like search behavior - new dal
$takeoption to define how many choices should be loaded - the model may contain a sibling property with initial enhanced objects for already selected options:
_<model key>_options; this can be populate using the model script:model["_child-roles_options"] = await IDVAult.globalQuery(null, 'roles', {$include: model["child-roles"]})using the below dal config - if a
$partitionis included in the result, it is shown before each match and choice; to ensure$partitionis added to each result set the server dal config optionloadDefaultPropertiestotrue(see below) - (since v2.8.19) forms(k5-select): when not defining
matchExpressionorlabelExpressionfallback tolabelProp
field.json
{
"type": "k5-select",
"key": "child-roles",
"templateOptions": {
"multiple": true,
"valueProp": "entryDN",
"labelExpression": "$item.name",
"descriptionExpression": "$item.description",
"matchExpression": "{{$item.name}} <small>{{_.truncate($item.description, {length: 15})}}</small>",
"dal": {
"key": "roles",
"async": true,
"options": {
"$take": 5
}
}
}
}
model.json
{
"child-roles": [
"cn=Finance,cn=Level30,cn=RoleDefs,cn=RoleConfig,cn=AppConfig,cn=User Application Driver,cn=driverset,o=system",
"cn=Level10,cn=Level10,cn=RoleDefs,cn=RoleConfig,cn=AppConfig,cn=User Application Driver,cn=driverset,o=system"
],
"_child-roles_options": [
{
"entryDN":"cn=Finance,cn=Level30,cn=RoleDefs,cn=RoleConfig,cn=AppConfig,cn=User Application Driver,cn=driverset,o=system",
"nrfLocalizedDescrs":{
"en":"Finance Department"
},
"nrfLocalizedNames":{
"en":"Finance"
},
"cn":"Finance",
"entryUUID":"60914df0-5edf-0941-b192-60914df05edf",
"$id":"60914df0-5edf-0941-b192-60914df05edf",
"$name":"Finance",
"$partition":{
"id":"k5",
"ui":{
"label":"Kenoxa",
"logo":"logo.png",
"icon":"Karma_symbol_blau.png"
}
},
"$type":"role",
"nrfStatus":"50",
"nrfRoleLevel":"30",
"nrfRoleCategoryKey":[
"default",
"favorites"
],
"name":"Finance",
"description":"Finance Department"
},
{
"entryDN":"cn=Level10,cn=Level10,cn=RoleDefs,cn=RoleConfig,cn=AppConfig,cn=User Application Driver,cn=driverset,o=system",
"nrfLocalizedDescrs":{
"en":"Level10, Permission Role"
},
"nrfLocalizedNames":{
"en":"Level10"
},
"cn":"Level10",
"entryUUID":"03ebaf0b-23d3-c740-9e81-03ebaf0b23d3",
"$id":"03ebaf0b-23d3-c740-9e81-03ebaf0b23d3",
"$name":"Level10",
"$partition":{
"id":"k5",
"ui":{
"label":"Kenoxa",
"logo":"logo.png",
"icon":"Karma_symbol_blau.png"
}
},
"$type":"role",
"nrfStatus":"50",
"nrfRoleLevel":"10",
"name":"Level10",
"description":"Level10, Permission Role"
}
]
}
html
since v2.8.8
This control allows to render an html expression. The key property is optional and may access a property within the model.
{
"type": "html",
"key": "isNew",
"templateOptions": {
"label": "Is New",
"expression": "<i class='fa fa-fw fa-{{model ? 'check-square-o' : 'square-o'}}'></i>"
}
}
button
Renders a <button />. The following templateOptions are supported:
text(deprecated since v2.11.4, uselabel)label(since v2.11.4): to displayicon(optional): font-awesome icon withoutfa-prefixbtnType: the button style (one of:default,primary,success,info,warning,dangerorlink)onClick: expression to evaluate, the model can be accessed asmodelclassName: additional css class names applied to the wrapperdiv
Since v2.11.4 these options maybe changed via
expressionProperties.
{
"type": "button",
"templateOptions": {
"text": "Accept",
"btnType": "primary",
"icon": "check",
"onClick": "model.accepted = !model.accepted"
},
"expressionProperties": {
"templateOptions.icon": "model.accepted ? 'check-square' : 'square'"
}
}
intro
since v2.20.0
Powered by intro.js
Renders a link to start a intro.
Example
{
"type": "intro",
"templateOptions": {
"steps": [
{
"element": "[data-form-field=\"user__password\"]",
"intro": "{{$index}} step"
},
{
"element": "[data-form-field=\"ctrl.form_input_cn_2\"]",
"intro": "Second tooltip",
"position": "right"
}
]
}
}
Translation example (config/i18n/formly/[locale].yaml)
types:
intro:
label: Hilfe
# Next button label in tooltip box
nextLabel: 'Weiter →'
# Previous button label in tooltip box
prevLabel: '← Zurück'
# Skip button label in tooltip box
skipLabel: 'Überspringen'
# Done button label in tooltip box
doneLabel: 'Fertig'
# Hint button label
hintButtonLabel: 'Verstanden'
Second tooltip: 'Zweiter Tooltip'
Template Options
Interpolated Properties
These properties are interpolated and then translated. If no translation is found the value is used as is.
'nextLabel': 'Next →'- Next button label in tooltip box'prevLabel': '← Back'- Previous button label in tooltip box'skipLabel': 'Skip'- Skip button label in tooltip box'doneLabel': 'Done'- Done button label in tooltip box'hintButtonLabel': 'Got it'- Hint button label
Value Properties
'label': 'label'- translated viatypes.intro.labelinconfig/i18n/formly/[locale].yaml'btnType': 'link'- button type'btnClass': undefined- additional css classes'icon': 'question-circle'- font-awesome icon withoutfa-prefix'steps': []- steps to render (see below for options)'hidePrev': false- Hide previous button in the first step? Otherwise, it will be disabled button.'hideNext': false- Hide next button in the last step? Otherwise, it will be disabled button.'tooltipPosition': 'auto'- Default tooltip box position,top,left,right,bottom,bottom-left-aligned(same asbottom),bottom-middle-aligned,bottom-right-alignedorauto(to detect the position of element and assign the correct position automatically). Default isauto'tooltipClass': ''- Next CSS class for tooltip boxes'highlightClass': ''- CSS class that is added to the helperLayer'exitOnEsc': true- Close introduction when pressing Escape button?'exitOnOverlayClick': true- Close introduction when clicking on overlay layer?'showStepNumbers': true- Show step numbers in introduction?'keyboardNavigation': true- Let user use keyboard to navigate the tour?'showButtons': true- Show tour control buttons?'showBullets': true- Show tour bullets?'showProgress': false- Show tour progress?'scrollToElement': true- Scroll to highlighted element?'scrollTo': 'element'- Should we scroll the tooltip or target element? Options are:elementortooltip'scrollPadding': 30- Padding to add after scrolling when element is not in the viewport (in pixels)'overlayOpacity': 0.8- Set the overlay opacity'positionPrecedence': ["bottom", "top", "right", "left"]- Precedence of positions, when auto is enabled'disableInteraction': false- Disable an interaction with element?'helperElementPadding': 10- Set how much padding to be used around helper element'hintPosition': 'top-middle'- Default hint position'hintAnimation': true- Adding animation to hints?'buttonClass': "introjs-button- additional classes to put on the buttons
Step Properties
'intro'- interpolated text (see above)'element'- css selector for the element; each form element itsidreflected in thedata-form-fieldattribute, this allows to use the id as an element selector:[data-form-field="field_id"]'tooltipClass': ''- Optionally define a CSS class for tooltip'highlightClass': ''- Optionally append a CSS class to the helperLayer'position': 'auto'- Optionally define the position of tooltip,top,left,right,bottom,bottom-left-aligned(same asbottom),bottom-middle-aligned,bottom-right-alignedorauto(to detect the position of element and assign the correct position automatically). Default isauto'scrollTo': 'element'- Should we scroll the tooltip or target element? Options are:elementortooltip'disableInteraction': false- Disable an interaction with element?
unique-input
since v2.8.10
This form control allows to check if an input field contains a unique value by performing a dal query and evaluating the result.
Example field configuration:
{
"type": "unique-input",
"key": "cn",
"templateOptions": {
"label": "Login Name",
"dal": {
"key": "users-by-cn",
"attribute": "cn"
}
},
"asyncValidators": {
"unique": {
"message": "'This Login Name is not unique.' | formlyTranslate"
}
}
},
Example dal query (local.yaml):
# ...
dal:
'users-by-cn':
type: 'ldap:list'
authz: 'user'
options:
base: '<%= users.base %>'
scope: '<%= users.scope %>'
filter: '<%= users.filter %>'
attributes: cn
query:
'cn!': 'cn'
It is possible to use other model values to populate the queryOptions (since v2.14.4):
[
{
"className": "row",
"fieldGroup": [
{
"type": "input",
"key": "department",
"className": "col-sm-4",
"templateOptions": { "label": "Department" }
},
{
"type": "input",
"key": "prefix",
"className": "col-sm-4",
"templateOptions": { "required": true, "label": "Prefix" }
},
{
"type": "unique-input",
"key": "suffix",
"className": "col-sm-4",
"templateOptions": {
"label": "Suffix",
"required": true,
"dal": { "key": "users-by-cn" }
},
"expressionProperties": {
"templateOptions.dal.queryOptions.cn": "model.prefix + '-' + model.suffix",
"templateOptions.dal.queryOptions.department": "model.department"
},
"asyncValidators": {
"unique": { "message": "'Es existiert bereits ein Benutzer mit diesem Namen.'" }
}
}
]
}
]
k5-paged-list
since v2.13.0
Allows to display a paginated DAL list. This is especially useful in combination with a search field:
[
{
"type": "input",
"key": "q",
"className": "col-sm-6",
"templateOptions": {
"placeholder": "Search ..."
},
"modelOptions": {
"debounce": { "default": 350, "blur": 0, "*": 150 }
}
},
{
"type": "k5-paged-list",
"className": "col-sm-6",
"templateOptions": {
"options": [],
"dal": {
"key": "accounts-search"
},
"fields": [{
"type": "html",
"templateOptions": {
"expression": "{{model.givenName}} {{model.sn}}"
}
}]
},
"expressionProperties": {
"templateOptions.dal.options.$q": "model.q"
}
}
]
Corresponding DAL definition:
dal:
'accounts-search':
type: 'ldap:list'
# admin, user (default) or guest
authz: 'user'
options:
base: '<%= accounts.base %>'
scope: '<%= accounts.scope %>'
filter: '<%= accounts.filter %>'
attributes:
entryDN cn givenName sn
qAttributes:
cn givenName sn
useServerSideSort: true
sortBy: cn
take: 10
json-tree
since v2.8.8
This control allows to render an json object as a tree. The key property is optional and may access a property within the model.
templateOptions:
rootName: This is an optional attribute that sets the title displayed at the root node. This is useful when you are showing sub-portions of an object or want the object root node to have a different string than thekeyor 'Model'.start-expanded: This is an optional attribute that designates if the tree's root should display as expanded initially.
{
"type": "json-tree",
"key": "treeDataProperty",
"templateOptions": {
"rootName": "Data Tree",
}
}
since v2.8.11
- color and indention matching global style
- used model values are customizable
Example:
[{
"type": "json-tree",
"key": "someKey",
"customize": "_.map(model, 'nested.model.path')"
}, {
"type": "k5-merge-ui",
"templateOptions": {
"fields": [{
"key": "urmAffiliations",
"label": "Category Data",
"isArray": true,
"rootName": "Category Data",
"jsonTreeCustomize": "_.map(model, 'affiliation.model')"
}]
}
}]
since v2.8.10
The json-tree from control now allows to customize the input object via an expression.
The following example shows how to display only a child property of the actual object.
Example field configuration:
{
"type": "json-tree",
"key": "myObject",
"templateOptions": {
"label": "My Object",
"customize": "_.map(model, 'data.model')"
}
}
Let's assume myObject is defined as follows:
[
{
id: 123,
data: {
foo: 'bar',
model: {
name: 'baz',
limit: 5,
isGreat: true
}
},
metadata: {
createdAt: '20170105121314Z'
}
},
{
id: 124,
data: {
foo: 'baz',
model: {
name: 'foo',
limit: 30,
isGreat: false
}
},
metadata: {
createdAt: '20170105121314Z'
}
}
]
json-tree would display the object like this:
[
{
name: 'baz',
limit: 5,
isGreat: true
},
{
name: 'foo',
limit: 30,
isGreat: false
}
]
dal-input
since v2.7.1
Karmas form controller dal-input can be used to fetch attributes using a DAL query and store the corresponding value directly into a text input field. The following is a example for a form definition that automatically fills first and last name as the user types a cn:
[{
key: 'cn',
type: 'input',
className: 'col-sm-6',
templateOptions: {
label: 'CN',
placeholder: 'Common Name',
required: true
}
}, {
key: 'firstName',
type: 'dal-input',
className: 'col-sm-6',
templateOptions: {
label: 'First Name',
placeholder: 'First Name',
required: false,
disabled: true,
valueProp: 'givenName',
dal: {
key: 'user-by-cn'
}
},
expressionProperties: {
'templateOptions.dal.options.queryCN': 'model.cn'
}
}, {
key: 'lastName',
type: 'dal-input',
className: 'col-sm-6',
templateOptions: {
label: 'Last Name',
placeholder: 'Last Name',
required: false,
disabled: true,
valueProp: 'sn',
dal: {
key: 'user-by-cn'
}
},
expressionProperties: {
'templateOptions.dal.options.queryCN': 'model.cn'
}
}]
The following configuration (local.yaml) shows the corresponding DAL entry.
dal:
# ...
'user-by-cn':
type: 'ldap:entry'
# admin, user (default) or guest
authz: 'user'
options:
base: '<%= users.base %>'
scope: 'sub'
filter: '<%= users.filter %>'
attributes: 'cn givenName sn'
requireUnique: false
query:
queryCN: cn
k5-tabset
k5-tabset is a simple form control to organize form inputs in tabs. It supports 3 templateOptions:
fields: an array of elements containing atabwith atitleand contentsjustified: iffalsethe tabs will only use the horizontal space they need to display the title. Iftrue, the tabs will use the whole width of the page. Default isfalse.vertical: iftruetabs will be displayed vertically, iffalsetabs will be displayed horizontally. Default isfalse.
The following shows a sample configuration:
[
{
"type": "k5-tabset",
"templateOptions": {
"justified": false,
"vertical": false,
"fields": [
{
"templateOptions": {
"title": "Personal Information",
"fields": [
{
"className": "row",
"fieldGroup": [
{
"type": "input",
"key": "givenName",
"className": "col-xs-12 col-sm-6",
"templateOptions": {
"label": "Given Name"
}
}, {
"type": "input",
"key": "surname",
"className": "col-xs-12 col-sm-6",
"templateOptions": {
"label": "Surname"
}
}
]
}
]
}
},
{
"templateOptions": {
"title": "Communication",
"fields": [
{
"className": "row",
"fieldGroup": [
{
"type": "input",
"key": "email",
"className": "col-xs-12 col-sm-6",
"templateOptions": {
"type": "email",
"label": "Email"
}
},
{
"type": "input",
"key": "phone",
"className": "col-xs-12 col-sm-6",
"templateOptions": {
"label": "Phone"
}
}
]
}
]
}
}
]
}
}
]
wizard
The wizard allows you to define multi-step forms while conditionally showing, hiding or skipping steps.
It supports these templateOptions:
navigationMode(default:false):- if not set or set to
falsethe next step is activated if the current stepcanExitExpressionreturnstrue - if set to
truenext and previous buttons are displayed which allow to change the active step
- if not set or set to
onFinishExpression: an expression to evaluate once the last step is completedsteps: an array of steps
Each step can have the following properties:
title: to show in step overviewdescription: to render as<h3 />before the stepfieldsdisabledExpression: determines if this step is disable and therefore hiddencanEnterExpression: determines if this step can be activatedonEnterExpression: evaluated once this step is activatedcanExitExpression: determines if the next step should be activatedonExitExpression: evaluated once this step is deactivatedfields: the step content as an array of fields
Within each expression property the model can be accessed as
model.
The following shows a sample configuration:
[
{
"type": "wizard",
"templateOptions": {
"navigationMode": true,
"steps": [
{
"title": "Personal Information",
"canExitExpression": "!!model.type",
"fields": [
{
"type": "radio",
"key": "type",
"templateOptions": {
"label": "User Type",
"theme": "custom",
"labelProp": "displayName",
"valueProp": "id",
"inline": true,
"required": true,
"options": [
{ "displayName": "Internal", "id": "internal" },
{ "displayName": "External", "id": "external" }
]
}
}
]
},
{
"title": "Internal",
"disabledExpression": "model.type !== \"internal\"",
"fields": [
{
"key": "workforceId",
"type": "input",
"templateOptions": { "label": "workforceId", "required": true }
}
]
},
{
"title": "External",
"disabledExpression": "model.type !== \"external\"",
"fields": [
{
"key": "email",
"type": "email",
"templateOptions": { "label": "email", "required": true }
}
]
}
]
}
}
]
The following show how to activate the next step once a model value has changed:
[
{
"type": "wizard",
"templateOptions": {
"steps": [
{
"title": "Personal Information",
"canExitExpression": "!!model.type",
"fields": [
{
"type": "radio",
"key": "type",
"className": "col-sm-12",
"templateOptions": {
"label": "User Type",
"theme": "custom",
"labelProp": "displayName",
"valueProp": "id",
"inline": true,
"required": true,
"options": [
{ "displayName": "Internal", "id": "internal" },
{ "displayName": "External", "id": "external" }
]
}
}
]
},
{
"title": "Internal",
"disabledExpression": "model.type !== \"internal\"",
"fields": [
{
"key": "workforceId",
"type": "input",
"className": "col-sm-12",
"templateOptions": { "label": "workforceId", "required": true }
}
]
},
{
"title": "External",
"disabledExpression": "model.type !== \"external\"",
"fields": [
{
"key": "email",
"type": "email",
"className": "col-sm-12",
"templateOptions": { "label": "email", "required": true }
}
]
}
]
}
}
]
additional controls
documentation comming soon