Scripting in checklists
The previous section introduced a wide variety of blocks that you can use to make your workbook/checklist more dynamic. In the following, we list where you can actually use those in iCL Designer.
Scripting the title of the inspectionβ
You can script the title of the inspections. Creating a script for the inspection title can come in very handy because then the inspectors won't have to enter a long title for each inspection manually. The inspection title scripts have a few constraints though that you have to keep in mind as a checklist designer.
The inspection title script must depend on exactly one checklist. This means, you have to use at least one field from a checklist in the title script and you cannot use fields from different checklists. Furthermore, the checklist that the title script depends on, must exist exactly once, meaning the minimum and maximum occurrences of that checklist must be 1.
π‘ Note that the title of the inspection will be updated every time when a specific field that is used in the title script is updated.
There are a few more things that you have to be aware of when you use a script to name the inspections:
- You have to be careful when using checklist fields that can be empty (i.e. that are not readonly fields with scripted answer). If a field that you use can be empty, you have to handle that case in the title script (probably a "test - if true - if false" block and a "has value" block will help you). Otherwise the title of the inspection will be empty which can be very confusing for the inspectors. Don't forget to handle fields that can be empty in the title script!
- Keep in mind: the title script is reevaluated every time when the user modifies the dependent checklist. This means, using for example the "now" Blockly block from the Date & Time group can be confusing. The value of "now" will be reevaluated every time when the checklist is modified, so the title will contain the last modification date.
Scripting properties of fieldsβ
The following images show the properties of a text field and a checkbox field.
Textfield | Checkbox |
---|---|
Blockly Field | Function |
---|---|
Title | The title script defines the display title of the field. |
Mandatory | The Mandatory script controls, whether the field is a mandatory field or not. |
Readonly | The Readonly script controls, whether the field can be edited or not. |
Exists | The Exists script controls, whether a field (and also subsequent fields) actually exists. If a field does not exist, it is neither shown to the user, nor is any of its data stored. |
Hidden | The Hidden script controls, whether the field (and thus also subsequent fields) is visible or not. As opposed to Exists, field values are still stored. That way, you can for example hide fields from the user that you only need for calculations. |
Scripted Answer | The Scripted Answer Script defines the response of the field. |
Data-bound query | This query defines filters and sorting order for content items. The result will be used to populate the available answers of e.g. a dropdown, a radio button, or a checkbox field. |
Data-bound list | This script must return a list of items. The result will be used to populate the available answers of e.g. a dropdown, a radio button, or a checkbox field. |
Blockly value and title differences in answer fieldsβ
Multiple choice questions (checkbox, radio button, dropdown, yes/no and 3-buttons) have a set of answers.
Answer fields have the 'Value' parameter. If this parameter is filled in (number or text), this value can be used instead of the title for Blockly comparisons.
Numbers specified in the "Value" parameter can also be used for calculation and mathematical comparison.
If a multiple choice question field is used for Blockly scripts, you can decide whether you want to use the titles or values of the corresponding answer fields for comparisons.
When using multilanguage workbooks: Titles can be translated, values cannot. Therefore you should always use values when making a comparison in a Blockly script, because it remains functional for all languages available in the workbook.
If for some reason you still have to use the titles in your script, keep in mind the following: the titles are returned as a concatenated text, while the values are returned as list to make further operations easier. So you can link values without any further ado, but the titles must be wrapped into a "make list from text" block with the delimiter: ", ". We suggest to always use the values instead of the titles.
Resolving titles in different languagesβ
In multilanguage workbooks, there is an additional option to resolve the titles using a specific translation (technically: culture).
You can select from all languages available in the workbook (using the ISO 639-1 two-letter language code), or the default setting 'of inspection', which will use the language the inspector selects for performing the inspection.
Scripting databound answersβ
There are cases in which you don't know all possible answers that the inspector should have available at the time of designing the checklist. For these cases, you can use different methods to provide available answers at runtime.
The two methods are
- creating a query to the database which loads content items, and
- providing a list of custom items in a blockly script.
Both methods will provide a list of items that will be used as available options for the e.g. checkbox field, radio button field, or any kind of selection question. You can enable the specific properties by checking on the "Has data-bound values" property.
This will automatically create a data-bound answer, which acts as a placeholder. You cannot remove or edit this answer, except when unchecking the "Has data-bound values" checkbox.
Feel free to add "static" answers before and after that placeholder.
In case of content items, the title
property of the content item is used as title of the option,
while the id
of the content item is used as the value
. For data-bound values, both title
and value
are stored, so if
the title
of the content item changes later on, the original title (at the time the checklist was saved) will
still be visible in the checklist and reports.
Binding available answers to a content item queryβ
If you want to use content items to fill the available answers, you can keep the default selection of "Bind answers to": Content items
.
First, you have to define the content type of the items you want to resolve, then you can define a query and add filters and sort descriptors to apply on the returned items. You can create the query by pressing the blockly button on the query property.
The query block has two inputs for filters and sort descriptors.
Using "display text" to define the title of the optionβ
By default, when using content items, the title
property of the content item is used as display text of the option.
This may not always be what you want to show to the user.
Instead, you can add a "display text" script. This will be evaluated for each content item and the result will be used as display text of the option.
To access fields of each individual item, use the block in the "properties of 'contenttypename'" category.
The "display text" property allows you to use fields of the checklist to create the display text. This can be useful if you want to show the user a combination of the content item and data from the checklist. However, once an option is selected by the user, its title will not be updated anymore. If you want this behavior, please enable the "live display text" property.
Using "live display text" to update the title of the optionβ
Whenever you enable "live display text", the title of any selected option will be updated whenever the any fields the query and display text scripts depend on are updated.
Live display texts were originally introduced for cases, where you use a content item to provide the available options of some option field (checkbox, dropdown) of a multi-language workbook. By default, the options of data bound fields show the title of a content item, which is not translated. Using 'display text' you can select the field of the content item that should be displayed based on the language - e.g. via some "select_language" field in the checklist.
For example, let's assume that we have a content type with the fields 'title_en' and 'title_de' which contain the respective translations. Now, if the language is 'en', return the 'title_en' field, if the language is 'de', return the 'title_de' field of the content item. Whenever you now change the language using the "select_language" field, any already selected options will not be translated, unless you enable the "live display text" option.
The following sample shows the difference of having "live display text" enabled or disabled.
Notice how - having "live display text" enabled - the selected options title changes from "Apple" and "Pineapple" to "Apfel" und "Ananas", when the language is changed.
- Live display text disabled
- Live display text enabled
iCL Designer will give you a validation error if you create a script that resolves the "titles" or "localized titles" of a data bound field with "live display text" enabled. The reason is that even though these titles may get updated, this change will not be propagated to dependent scripts. In other words: Your script will not be notified that the title has changed.
Binding available answers to a simple listβ
In many cases, you will only need a simple list of items that provide the available options. Creating and
managing content items in the database would be too much additional effort. For these cases, you can select to bind the answers to Elements in list
, which gives you the default blockly editor to create any list of items.
You can use any combination of blocks, e.g. answer of
(including repeated scopes), create list with
,
make list from text
, and so on.
Auto-select a single databound answerβ
There are cases, when the list of the databound answers contains only one option. In these cases you can configure that single databound answer to be automatically selected. You can enable the auto-selection by checking on the "auto-select" property.
The following example shows this feature using a simple list of items.
π‘ Note that you can also use auto-selection if you created a query for databound answers, not just with a list of databound values.
There are three different fields in this example: a checkbox, a radio button and a dropdown. When the list has one option only, that option is selected in all three fields.
Limitationsβ
If you are using follow-up fields on answers, you can only use them on selection fields that have a single value, like radio buttons, dropdowns, yes/no, and three-button fields. Because the follow-up field would have to be "repeated" for each answer, it is not currently supported (as of January 2021). To work around this, you can create another headline and use Repeat for elements in list.
Do | Don't |
---|---|
Scripting properties of chapters/headlinesβ
The properties of chapters and headlines differ a bit, as they cannot store any value themselves (no Scripted Answer), but can be repeatable.
Blockly Field | Function |
---|---|
Title | The title script defines the display title of the chapter/headline. You can use it to dynamically display its contents by using one of the fields of the chapter/headline. |
Exists | The Exists script controls, whether a chapter/headline exists at all. If Exists is false, no data of the chapter/headline and any of its contained fields will be stored. Note, that Exists always affects all existing instances of a chapter/headline: If you repeated a chapter three times (i.e. you have 3 instances of that chapter) and Exists turns false , all three chapters will be removed. |
Hidden | The Hidden script controls, whether the chapter/headline (and any of its fields) is visible or not. As opposed to Exists, Hidden only affects one single instance. So you could have three repeated chapters and bind their Hidden script to some contained yes/no field of the chapter. If you set this to No in any of the three chapters, the other two will still be visible. This is a very important distinction to Exists. |
Repeat for | This setting allows create (or "repeat") chapters/headlines for a given set of data. This can be Inspected items (foreach content item that is inspected), Related items (for each child item matching the specified query) and Element in list (for each element in a list). Those options are described further below |
Minimum | If a chapter/headline is repeatable, Minimum specifies the minimum count of chapters/headlines that must be related. |
Maximum | If a chapter/headline is repeatable, Maximum specifies the maximum count of chapters/headlines. Once the maximum is reached, the user cannot ad any more instances of the chapter/headline |
Index field | For repeated sections (headlines or chapters), an index field can be specified. This number field will be automatically filled with the index of the current section whenever one is added, deleted or the sorting is changed. So, for example, if you have headlines for three defects "Defect 1", "Defect 2" and "Defect 3", they will have the following indices: "Defect 1" will have index 0, "Defect 2" will have index 1, "Defect 3" will have index 2. Important Indices are zero-based. They start at 0 and not at 1! |
Order by | If a chapter/heading is repeatable, Order by specifies in which order the repeated chapters/headings should be displayed. This way they can be sorted dynamically |
Repeat for inspected itemsβ
When selecting repeat for Inspected items on e.g. a chapter, a chapter will be added for each content item that is being inspected in the current inspection. Inspected items can be set on the task, or when the user starts an inspection without a task and selects an item from the list. This only works, if the workbook is configured to require an inspected item. In the following sample, we have a building check workbook, that defines a content type tutorial_building as its inspected type. Therefore, the user must select a building when starting an inspection.
Then, we can define a repeatable chapter, that is created for each tutorial building.
Note, that we must specify a *context field*. This is a *content item field* which stores the building that a chapter was created for. This way, you always know which chapter exists for which building and you can utilize this in your scripts.You can download a demo workbook from here πΎ
Repeat for related itemsβ
Repeat for related items allows you dynamically load items. The only restriction for now is, that they need to be child-items. (Parent-child relationship) This can be used, for example, to load all defects of a given building into the current checklist:
As you can see, you get an additional scriptable property query. This already defines the parent filter, but you can add additional filters. Those filters can be either constant (only showing defects with a severity of at least 5) or even dynamic, using fields of the checklist (only showing defects whose location is ort)
You can download a demo workbook from here πΎ
Repeat for elements in listβ
While repeat for related items and inspected items require you to work with content types, repeat for elements in list allows you to create chapters/headlines for any list.
As an example, we show you a checklist of the demo workbook, that you can download from here πΎ
It creates a headline for each finding that was selected in the field defect_categories
As you can see, the list property looks very similar to a Scripted Answer property. It expects you to return a list.
If your script only returns a single value (some text or number), it is automatically wrapped in a list for you.
One thing to note is that, as with repeat for related and repeat for inspected items, you do need a context field. This is, because you can change the selected findings any time, thus, changing the list that the headline is bound to. In that case, the system needs to know which headline instance was created for which list element, so that it can remove ones that are not part of the list anymore and add headlines for new list elements. For this reason, it is very important, that the context field can actually hold any value, that could be in that list. E.g. if your list contains text, you should not use a number field as a context field! If you have no idea what could be in that list, you better use a text field, as this can hold almost any value. The downside is, that it may not be as descriptive.
As we use a finding field as the source of our list, we can safely use another finding field as the context field of our headline:
How to create a listβ
Lists can be retrieved in checklists in various ways. The following samples can also be found in the demo workbook πΎ
One would be to create your list script using the create list block:
Another one would be to split a string into a list of elements:
Another one would be to use a field, which is contained in a repeatable section (chapter/headline)
Note that the field `defect_categories` is a dropdown field, so it only allows a single answer and, thus, does not return a list out of the box.
Note, that you could end up with a list of lists. This may sound complicated, but is actually quite easy. If you, for example, create your list script using the create list block, and in that block, you use a catalog field or a field that is contained in a repeatable section, you already a list of lists. For this scenario, we provide the flatten block. This simply takes a list and, in case this list contains another list, it simply moves all its elements to the outer list. Therefore, you can say that it flattens the list.
This is an advanced scenario, so please have a look at the two List of lists checklists in the demo workbook πΎ
Dynamically sort chapters and headings using 'Order by'β
Using 'Order by' you can dynamically change the order of chapters and headings. To do this, you specify in blocks by which property (which field) a section should be sorted. In addition it must be indicated by means of 'descending' whether ascending or descending order is to be sorted.
The following video shows the functionality in action - chapters are sorted dynamically in ascending and descending order:
Sort areas by multiple criteriaβ
You can sort by any number of properties. In the following example
- first sorted by the value
sort
in ascending order. - then by the value
category
but in descending order.
So there should be three headings with the following values
- Heading 1:
sort
: 1,category
"b" - Heading 2:
sort
: 2,category
"a" - Heading 3:
sort
: 1,category
"c"
then the headings are sorted primarily by the first OrderBy property sort
in ascending order.
This results in the following order
- Heading 1 (
sort
: 1) - Heading 3 (
sort
: 1) - Heading 2 (
sort
: 2)
Next, sort in descending order by the second OrderBy property category
. This results in the final order:
- Heading 3 (
category
: c) - Heading 1 (
category
: b) - Heading 2 (
category
: a)
It is important to note that, according to its category
, heading 2 should be ranked before all other headings. However, the ranges were primarily sorted by the sort
property.
So the order of the order by
blocks is crucial!
Limitationsβ
When sorting chapters and headings, the following should now be noted:
a field used for sorting must necessarily be defined in the area that will be sorted:
the
This value must then be defined outside the sorted range. Should it be defined _inside_, it could be that for two different ranges a different value exists, i.e. one range wants to be sorted _ascending_ and another _descending_. This would lead to unpredictable sorting results and is therefore not allowed.descending
part of anorder by
block does not have to be a constant value, as in the previous examples. It can also be set dynamically using a field from the checklist. In the following example ayes/no
field is used to determine whether chapters should be sorted ascending or descending:Theoretically, you can use the test block to define at runtime by which property a range should be sorted. In the following example the field
Again, this can lead to unpredictable sort orders. One heading may already have the `sort` value filled, but another may not. This causes sorting by `sort` and `category`! In addition, `sort` and `category` are two different field types: `sort` is a number whereas `category` is a text. If different value types are used in sorting, these values must all be converted to the same type, otherwise sorting is not possible. The only type that any value can be converted to is a **text**. Therefore, in case of type conflicts, all values are converted to a text before sorting.sort
is only sorted by if it has a value set. Otherwise it will be sorted bycategory
.
In the Demo workbook πΎ both scenarios (sorted chapter and sorted heading) are demonstrated.
Advanced list blocksβ
How to use 'Filter list' blockβ
When working with lists you may want use only a subset/part of the list. In such cases, you can use the filter block to filter out any unwanted elements of the list.
Remember: There are various sources of lists such as
- lists created by other blocks (e.g. create list with, make list from text, etc.),
- the values of an options field (e.g. checkbox, dropdown, etc.),
- or simply the value of fields that are placed within a repeatable headline or chapter.
The filter block takes two parameters:
- a list to be filtered
- and a block (or combination of blocks) that returns true or false that is used to decide whether an element of the given list should be included in the result or not.
The logical block is applied to each and every element of the given list and if it returns true, that certain element will be included in the resulting list, otherwise not. Therefore the provided logical block(s) must use the given element block.
Let's see a few examples.
Filtering numbers less than 3β
Let's assume there is a checkbox - where the user can select numbers between 1 and 5 - stored in a field called numbers.
To filter the numbers that are less than 3, we can pass the values of the numbers field to the filter block and a math block to compare the elements of the list to 3.
The result in iCL Filler:
Filtering numbers that are exactly 3 or 5β
We use the same checkbox called numbers again. The Blockly script is very similar as before but as you can see it uses the element block twice. You have to use it at least once but you can use it more than once.
A few more examples are presented in the Demo workbook πΎ.
How to use 'any/every' blockβ
The 'any/every' block takes two parameters: a list and a boolean expression. It checks whether any/every element in the given lists fulfills this expression or not. It returns true or false.
Let's see an example. Given a list with numbers. We would like to answer two easy yes/no questions:
- Is every element in the list less then 3?
- Is there an odd number in the list?
In case of the first question the script is the following:
The second script is similar but here we select 'any' from the dropdown. In the boolean expression, we check if the element is odd, i.e. if the remainder is not 0 when divided by 2.
The result of the above scripts in the Filler looks like the following:
How to use 'list map' blockβ
The 'map' block can be used to create a new list from a list by transforming each element of the original list into a new value - this new value can be anything: text, number, list, etc.
You have to pass the original list and an expression that will be executed on every element one by one.
In the following example, we transform a list of numbers into another list of numbers by multiplying each element of the original list by 2. This is how this script looks like:
And the result:
How to use 'sort list with expression' blockβ
The 'sort list with expression' block is a combination of a simple sort and the above explained map. We sort the elements of a list by a value that we create in the second parameter of the block. You have to specify an expression that will be executed on each element of the list - just like by the 'map' block - then the values will be sorted by these values.
Let's see an example: we sort a list of texts not alphabetically but by the length of the words.
The result in the Filler is the following:
You can download a Demo workbook πΎ to see a few examples of the above described blocks.