Skip to content

Commit

Permalink
Cleaning up and adding lots of docs about options (code lists / svara…
Browse files Browse the repository at this point in the history
…lternativer) (#1934)

Co-authored-by: Ole Martin Handeland <[email protected]>
  • Loading branch information
olemartinorg and Ole Martin Handeland authored Dec 19, 2024
1 parent 8b45be0 commit d83b894
Show file tree
Hide file tree
Showing 43 changed files with 2,281 additions and 1,126 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ The municipality of Sogndal wishes to collect information on the newcomers emplo
### In Local Development environment

1. Create the directory `App/options` if it does not exist.
2. The municipality of Sogndal has created a [static code list](/altinn-studio/guides/development/options/static-codelists) for **industries**: [industry.json](../industry.json). Download the file and place it in `App/options`.
3. Set up the values in the code list for **Years in work force** as an [open dynamic code list](/altinn-studio/guides/development/options/dynamic-codelists) in `App/options` (follow the directions in the documentation).
2. The municipality of Sogndal has created a [static code list](/altinn-studio/guides/development/options/sources/static) for **industries**: [industry.json](../industry.json). Download the file and place it in `App/options`.
3. Set up the values in the code list for **Years in work force** as an [open dynamic code list](/altinn-studio/guides/development/options/sources/dynamic) in `App/options` (follow the directions in the documentation).
Options:
Label | Data value
--------------|----------
Expand All @@ -62,8 +62,8 @@ The municipality of Sogndal wishes to collect information on the newcomers emplo

### Useful documentation

- [Static code lists](/altinn-studio/guides/development/options/static-codelists)
- [Dynamic code lists](/altinn-studio/guides/development/options/dynamic-codelists)
- [Static code lists](/altinn-studio/guides/development/options/sources/static)
- [Dynamic code lists](/altinn-studio/guides/development/options/sources/dynamic)

### Knowledge check
{{% expandsmall id="m4t1q1" header="What is the difference between static and dynamic options?" %}}
Expand Down Expand Up @@ -94,12 +94,12 @@ We want the user to be presented with a different set of options for the industr

### Tasks

1. [Send a dynamic query parameter](/altinn-studio/guides/development/options/#pass-query-parameters-when-fetching-options) with the Industry component based on the Sector.
1. [Send a dynamic query parameter](/altinn-studio/guides/development/options/sources/dynamic#query-parameters) with the Industry component based on the Sector.
2. Create a dynamic code list for _Industry_ with logic based on the value of the query parameter (hint: you can read the industry list from the JSON file).

### Useful documentation
- [How to pass query parameters when fetching options](/altinn-studio/guides/development/options/#pass-query-parameters-when-fetching-options)
- [How to configure dynamic code lists](/altinn-studio/guides/development/options/dynamic-codelists)
- [How to pass query parameters when fetching options](/altinn-studio/guides/development/options/sources/dynamic/#query-parameters)
- [How to configure dynamic code lists](/altinn-studio/guides/development/options/sources/dynamic)

### Knowledge check
{{% expandsmall id="m4t2q1" header="If a code list is configured with a mapping to the data model, what happens when the relevant field changes value?" %}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ Sogndal kommune ønsker å samle inn opplysninger om tilflytterens arbeidsituasj
### I lokalt utviklingsmiljø

1. Opprett mappen `App/options` hvis den ikke eksisterer.
2. Sogndal kommune har opprettet en [statisk kodeliste](/nb/altinn-studio/guides/development/options/static-codelists) for **bransjer**: [industry.json](../industry.json). Last ned filen og plasser den i `App/options`.
3. Sett opp alternativene for **År i arbeidslivet** som en [åpen dynamisk kodeliste](/nb/altinn-studio/guides/development/options/dynamic-codelists#åpne-dynamiske-kodelister) i mappen `App/options` (følg anvisning i dokumentasjonen).
2. Sogndal kommune har opprettet en [statisk kodeliste](/nb/altinn-studio/guides/development/options/sources/static) for **bransjer**: [industry.json](../industry.json). Last ned filen og plasser den i `App/options`.
3. Sett opp alternativene for **År i arbeidslivet** som en [åpen dynamisk kodeliste](/nb/altinn-studio/guides/development/options/sources/dynamic#åpne-kodelister) i mappen `App/options` (følg anvisning i dokumentasjonen).
Svaralternativer:
Label | Dataverdi
-----------|----------
Expand All @@ -60,8 +60,8 @@ Sogndal kommune ønsker å samle inn opplysninger om tilflytterens arbeidsituasj

### Nyttig dokumentasjon

- [Statiske kodelister](/nb/altinn-studio/guides/development/options/static-codelists)
- [Dynamiske kodelister](/nb/altinn-studio/guides/development/options/dynamic-codelists)
- [Statiske kodelister](/nb/altinn-studio/guides/development/options/sources/static)
- [Dynamiske kodelister](/nb/altinn-studio/guides/development/options/sources/dynamic)

### Forståelsessjekk
{{% expandsmall id="m4t1q1" header="Hva er forskjellen på statiske og dynamiske svaralternativer?" %}}
Expand Down Expand Up @@ -95,12 +95,12 @@ basert på hvilken sektor de har krysset av for.

### Oppgaver

1. [Send en dynamisk query-parameter](/nb/altinn-studio/guides/development/options/#sende-med-spørringsparametere-ved-henting-av-en-kodeliste) med Bransje-komponenten basert på Sektor.
1. [Send en dynamisk query-parameter](/nb/altinn-studio/guides/development/options/sources/dynamic#spørringsparametre) med Bransje-komponenten basert på Sektor.
2. Lag en dynamisk kodeliste for _Bransje_ med logikk basert på verdien til query-parameteren (hint: du kan lese inn bransjelisten fra json-filen).

### Nyttig dokumentasjon
- [Hvordan sende med spørringsparametre ved henting av kodelister](/nb/altinn-studio/guides/development/options/#sende-med-spørringsparametere-ved-henting-av-en-kodeliste)
- [Hvordan sette opp dynamiske kodelister](/nb/altinn-studio/guides/development/options/dynamic-codelists)
- [Hvordan sende med spørringsparametre ved henting av kodelister](/nb/altinn-studio/guides/development/options/sources/dynamic#spørringsparametre)
- [Hvordan sette opp dynamiske kodelister](/nb/altinn-studio/guides/development/options/sources/dynamic)

### Forståelsessjekk
{{% expandsmall id="m4t2q1" header="Om en kodeliste er satt opp med en mapping mot datamodellen, hva skjer når det aktuelle feltet endrer verdi?" %}}
Expand Down
273 changes: 28 additions & 245 deletions content/altinn-studio/guides/development/options/_index.en.md
Original file line number Diff line number Diff line change
@@ -1,263 +1,46 @@
---
title: Code lists (options)
linktitle: Code lists
description: How to configure Options / Code lists for an app?
title: Code lists and options
linktitle: Options
description: How to set up code lists for components that use options
toc: true
weight: 40
aliases:
- /altinn-studio/guides/options
- /altinn-studio/reference/data/options
---

Altinn offers two different ways an application can use code lists - static and dynamic. Both is primarily exposed
through the options api from application, and are available at `{org}/{app}/api/options/{optionsId}`.
Checkbox, Dropdown, and RadioButton components will automatically be able to fetch such lists if you connect the
component to the option id in question. Not all dynamic code list have to be fetched from the options api - we can also
have code lists based on the values from a repeating structure in the datamodel.
Several of the form components in Altinn 3 use options. By options, we mean a list of choices that can be selected by
the user. In the most basic use-cases you might [set up a list of options directly in the component configuration](sources/static),
but often you'll want to fetch the options from a _code list_.

## Connect the component to options (code list)
### Terms

This is done by adding the optionId you would like to refer to either through the component UI in Designer or directly
in `FormLayout.json` as shown below:
There are subtle differences between the terms _options_ and _code lists_:

```json
{
"id": "some-dropdown-component",
"type": "Dropdown",
"textResourceBindings": {},
"dataModelBindings": {},
"optionsId": "countries"
}
```
- **Options**: A list of choices that can be selected by the user. Think of the contacts in your phone. When you use
your contact list to dial someone, you are selecting from a list of options, and your phone uses the selected value
(the phone number) to dial the person.
- **Code list**: A list of codes and their corresponding value and texts. Think of
the [ISO 3166-1](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) country codes. This list contains codes (like `NO`
or `SE`) and their corresponding labels (like `Norway` or `Sweden`).

### Save label value in the datamodel
Sometimes you might wish to save the displayed value in the users chosen language to simplify creation of simple presentations of data without addtional lookups or a requirement to remember the label the user actually picked in case it have changed over time.
When selecting a value from (for example) a Dropdown component, you are selecting from a list of _options_, which
might be sourced from a _code list_. In that case, options is _what they are_, and a code list is _where they came from_.

This is performed by having a separate ``dataModelBindings`` with the key ``"label":`` in addition to ``"simpleBinding":``
### Supported components

```json
{
"id": "dropdown-component",
"type": "Dropdown",
"dataModelBindings": {
"simpleBinding": "soknad.nyGaranti.loyvetype",
"label":"soknad.nyGaranti.loyvetypeLabel"
},
"optionsId": "biler"
}
```
The following components support options:

| Component | Type | Use case |
|-------------------------------------------------------------------------|-----------------------|----------------------------------------------------------------------------------------------------|
| [Dropdown](../../../reference/ux/components/dropdown) | Single choice | Used to select a single option from a dropdown list |
| [RadioButtons](../../../reference/ux/components/radiobuttons) | Single choice | Used to select a single option from a list of radio buttons |
| [List](../../../reference/ux/components/listcomponent) | Single choice | Used to select a single option from a list/table (with one radio button per row) |
| [Likert](../../../reference/ux/components/likert) | Single choice per row | Used to select a single option per row in a table, displayed as a scale. Commonly used in surveys. |
| [Checkboxes](../../../reference/ux/components/checkboxes) | Multiple choice | Used to select one or more options from a list of checkboxes |
| [MultipleSelect](../../../reference/ux/components/multipleselect) | Multiple choice | Used to select one or more options from a dropdown list |
| [FileUploadWithTag](../../../reference/ux/components/fileuploadwithtag) | Single choice | Used to upload a file and tag it with an option |

## Pass query parameters when fetching options

Options supports query parameters when making the api call, the parameter `language` is added automatically.

### Pass static query parameters

You can add static query parameters by setting the `queryParameters` property on the component:

```json
{
"id": "some-dropdown-component",
"type": "Dropdown",
"textResourceBindings": {
"title": "NyGarantiLoyvetype"
},
"dataModelBindings": {
"simpleBinding": "soknad.nyGaranti.loyvetype"
},
"required": true,
"optionsId": "loyvetyper",
"queryParameters": {
"loyvetype": "garanti"
}
},
```

In the example above the parameter `?loyvetype=garanti` will be added to the request.

### Pass dynamic query parameters based on the data model

You can add dynamic parameters by setting the `mapping` property on the component:

```json
{
"id": "some-dropdown-component",
"type": "Dropdown",
"textResourceBindings": {
"title": "NyGarantiLoyvetype"
},
"dataModelBindings": {
"simpleBinding": "soknad.nyGaranti.loyvetype"
},
"required": true,
"optionsId": "loyvetyper",
"mapping": {
"soknad.transportorOrgnummer": "orgnummer"
}
},
```

In the example above, the query parameter `orgnummer={nr}`, where `{nr}` is the value of `soknad.transportorOrgnummer`
will be set.
If an option is setup with mapping and the given data field changes app-frontend will refetch the option. This can be
used to dynamically decide which choices are available based on information given by the end user.

Passing query parameters from repeating groups is also supported by adding an index indicator for the relevant indexes.
Example for a group:

```json
{
"id": "dropdown-group",
"type": "Dropdown",
"textResourceBindings": {
"title": "Select city"
},
"dataModelBindings": {
"simpleBinding": "Group.City"
},
"required": true,
"optionsId": "cities",
"mapping": {
"Group[{0}].Country": "country"
}
},
```

For nested groups follows the same pattern but with an additional index indicator for the nested group:

```json
{
"id": "dropdown-nested-group",
"type": "Dropdown",
"textResourceBindings": {
"title": "Select city"
},
"dataModelBindings": {
"simpleBinding": "Group.SubGroup.City"
},
"required": true,
"optionsId": "cities",
"mapping": {
"Group[{0}].SubGroup[{1}].Country": "country"
}
},
```

For a complete example of how this is setup see our [demo app.](https://altinn.studio/repos/ttd/dynamic-options-rep)

{{%notice warning%}}

**Applies to applications using version 7.4.0 or older of the nuget packages** - https://github.com/Altinn/app-lib-dotnet/release

<br>

During PDF-generation the app will try to call the same option endpoint as app-frontend does.
We currently have a weakness where mapping parameters not are included in this request, see issue [#7903.](https://github.com/Altinn/altinn-studio/issues/7903)

A possible workaround here is to return an empty array when the PDF-generator asks for options with empty query params, example:

```c#
string someArg = keyValuePairs.GetValueOrDefault("someArg");
string someOtherArg = keyValuePairs.GetValueOrDefault("someOtherArg");

if (string.IsNullOrEmpty(someArg) || string.IsNullOrEmpty(someOtherArg)) {
return await Task.FromResult(new List<AppOption>());
}
```

Notice that this wil result in the option value and not the label being present as the end users answer.
{{% /notice%}}

### Store metadata for the parameters used to retrieve options in tha datamodel

You can store metadata for the parameters used to retrieve options in the datamodel by setting the `metadata` property
on the components `dataModelBinding` property:

```json
{
"id": "some-dropdown-component",
"type": "Dropdown",
"textResourceBindings": {
"title": "NyGarantiLoyvetype"
},
"dataModelBindings": {
"simpleBinding": "soknad.nyGaranti.loyvetype",
"metadata": "soknad.transportorOrgnummer"
},
"required": true,
"optionsId": "loyvetyper",
"mapping": {
"soknad.transportorOrgnummer": "orgnummer"
}
},
```

This configuration will store the metadata of the retrieved options as a comma separated string in the
field `soknad.transportorOrgnummer` in the datamodel.

## Description and HelpText

`description` and `helpText` is supported by options in apps that use version v7.8.0 or higher. `description` and
`helpText` can be displayed by the components `RadioButtons` and `Checkboxes` by providing the option list with the
mentioned properties.

Descriptions and HelpTexts can be provided to `options` in the same way that a `label` is provided, in either static or
dynamic code lists. One can also use them in options based on repeating groups in the `source` attribute.

```json
[
{
"value": "norway",
"label": "Norge",
"description": "This is a description",
"helpText": "This is a help text"
},
{
"value": "denmark",
"label": "Danmark"
}
]
```

```cs
var options = new AppOptions
{
Options = new List<AppOption>
{
new AppOption
{
Label = "Ole",
Value = "1",
Description = "This is a description",
HelpText = "This is a help text"
},
new AppOption
{
Label = "Dole",
Value = "2"
}
}
};
```

Descriptions and help texts used in options based on repeating groups can be set up with dynamic text-resources in the
same way as labels, described in
[options based on repeating groups](repeating-group-codelists).

```json
{
"id": "checkboxes-component-id",
"type": "Checkboxes",
...
"source": {
"group": "some.group",
"label": "checkboxes.label",
"description": "checkboxes.descripiton",
"helpText": "checkboxes.helpText",
"value": "some.group[{0}].someField"
}
},
```
In the categories below, you can learn more about how to produce a list of options, configure that option list to be used in a component, as well as common functionality supported across these components.

{{<children />}}
Loading

0 comments on commit d83b894

Please sign in to comment.