Module 4
Add code lists manually, programmatically and dynamically
In this module, you’re expanding the application you made in the previous modules to support more of the requirements of the municipality of Sogndal.
Topics covered in this module:
- Code lists/Options
- Dynamic expressions
Tasks
In many applications there is a need to provide the user with a set of response options for a data field. These options are referred to as code lists or options.
In Altinn Studio, options are supported by the radio buttons, checkboxes, dropdown, and multiple select components.
There are three ways to configure code lists (add options) in Altinn:
- By manually adding options for the component through Altinn Studio or in the file
{page}.json
. - By having the component fetch options from a static json-file.
- By dynamically generate options through application logic.
In this task, you will get to try out all three ways to configure a code list.
The municipality of Sogndal wishes to collect information on the newcomers employment. Data they wish to collect include which sector and industry the newcomer works in and how many years the newcomer has been active in the workforce.
In Altinn Studio
- Create a new form page to collect employment related data.
- Add a radio button component for Sector. Create the answer options
Offentlig
andPrivat
manually. - Add a check box component for Industry.
Choose Kodeliste as method for adding checkboxes and add Kodeliste ID
industry
. The rest of the setup for this component is done locally. - Add a dropdown list for Years in work force. Add Kodeliste ID
years-in-work-force
. The rest of the setup for this component is done locally. - Save your changes in Designer and and pull them to your local development environment.
In Local Development environment
Create the directory
App/options
if it does not exist.The municipality of Sogndal has created a static code list for industries: industry.json. Download the file and place it in
App/options
.Set up the values in the code list for Years in work force as an open dynamic code list in
App/options
(follow the directions in the documentation).
Options:Label Data value 0 - 5 years 0-5
5 - 10 years 5-10
10 - 20 years 10-20
20+ years 20+
Verify that all code lists works as expected.
Useful documentation
Knowledge check
Instance.Read
rights).In some cases, the values displayed in a code list may depend on another form field.
The municipality of Sogndal wants the list of industries to be personalised based on which sector the user works in.
Requirements from the municipality
We want the user to be presented with a different set of options for the industry choice based on which sector they work in.
- Private sector: Standard list of industries
- Public sector:
State
andMunicipality
Tasks
- Send a dynamic query parameter with the Industry component based on the Sector.
- 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
Knowledge check
Requirements from the municipality
If the user chooses IKT (data/it)
under industry, a text with a link to our overview of vacant positions should appear.
Below the industry choice, the following text should appear
Vi ser at du besitter kompetanse vi trenger i kommunen. Se en oversikt over våre ledige stillinger her.
Line 2 in the text should be a link that directs to https://sogndal.easycruit.com/index.html
The text and link should only be visible if the user has chosen IKT (data/it)
.
Tasks
- Add a component that can display the current text.
- Add dynamics to the component that make it visible only if
IKT (data/it)
is selected (NOTE: The text should also be displayed when multiple options are selected, as long as one of them isIKT (data/it)
). - Move the ‘Submit’ button to the employment section.
Useful documentation
Knowledge check
- If you add a new function to
RuleHandlerHelper
- where will it run?- Would dynamic work without this defined?
- What is the correlation between functions defined in
RuleHandlerObject
and the fileRuleConfiguration.json
?
Summary
In this module you have configured dropdown, radio button and checkbox components and added options for them manually, programmatically and dynamically.
The service should run on your local computer with localtest and it should be possible to select the expected option from each component.
Remember to push your local changes so that they become available in Altinn Studio
Solution
Add components in Altinn Studio Designer, add an appropriate header, and link the component to the correct field in the data model.
Adding options manually: Fill in fields in Altinn Studio Designer. In the code, it appears as follows:
App/ui/layouts/Arbeidsforhold.json
{
"$schema": "https://altinncdn.no/toolkits/altinn-app-frontend/4/schemas/json/layout/layout.schema.v1.json",
"data": {
"layout": [
{
"id": "RadioButtons-sektor",
"type": "RadioButtons",
"dataModelBindings": {
"simpleBinding": "Innflytter.Arbeidsinformasjon.Sektor"
},
"required": true,
"options": [
{
"label": "arbeidsforhold.sektor.offentlig",
"value": "offentlig"
},
{
"label": "arbeidsforhold.sektor.privat",
"value": "privat"
}
],
"textResourceBindings": {
"title": "arbeidsforhold-sektor.title"
}
},
...
]
}
}
Adding a static code list for industry: Place the file
industry.json
inApp/options
.Adding a dynamic code list for years in the workforce:
App/options/YearsInWorkForceOptionsProvider.cs
using Altinn.App.Core.Features;
using Altinn.App.Core.Models;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Altinn.App.AppLogic.Options
{
public class YearsInWorkForceOptionsProvider : IAppOptionsProvider
{
public string Id { get; set; } = "years-in-work-force";
public Task<AppOptions> GetAppOptionsAsync(string language, Dictionary<string, string> keyValuePairs)
{
var options = new AppOptions
{
Options = new List<AppOption>
{
new() {
Label = "0 - 5 år",
Value = "0-5"
},
new() {
Label = "5 - 10 år",
Value = "5-10"
},
new() {
Label = "10 - 20 år",
Value = "10-20"
},
new() {
Label = "20+ år",
Value = "20+"
}
}
};
return Task.FromResult(options);
}
}
}
- Register dynamisk code list:
App/Program.cs
...
{
// Register your apps custom service implementations here.
services.AddTransient<IInstantiationProcessor, InstantiationProcessor>();
services.AddTransient<IAppOptionsProvider, YearsInWorkForceOptionsProvider>();
...
}
To send a query parameter with the Industry component, we add a mapping to the component linked to the Sektor
field in the data model:
App/ui/layouts/arbeidsforhold.json
...
{
"id": "Checkboxes-bransje",
"type": "Checkboxes",
"dataModelBindings": {
"simpleBinding": "Innflytter.Arbeidsinformasjon.Bransje"
},
"required": true,
"textResourceBindings": {
"title": "arbeidsforhold-bransje.title"
},
"optionsId": "industry",
"mapping": {
"Innflytter.Arbeidsinformasjon.Sektor": "sektor"
}
},
...
- Dynamic code list for Industry with response options that depend on the value of
sektor
:
App/options/IndustryOptions.cs
using Altinn.App.Core.Features;
using Altinn.App.Core.Models;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
namespace Altinn.App.AppLogic.Options
{
public class IndustryOptions : IAppOptionsProvider
{
public string Id { get; set; } = "industry";
private List<AppOption> _privateOptions = null;
public Task<AppOptions> GetAppOptionsAsync(string language, Dictionary<string, string> keyValuePairs)
{
string sektor = keyValuePairs.GetValueOrDefault("sektor");
if (sektor == "offentlig")
{
var offentligeOptions = new AppOptions
{
Options = new List<AppOption>
{
new() {
Label = "Stat",
Value = "stat"
},
new() {
Label = "Kommune",
Value = "kommune"
},
}
};
return Task.FromResult(offentligeOptions);
}
else
{
if (_privateOptions == null)
{
using (StreamReader r = new("./options/industry.json"))
{
string json = r.ReadToEnd();
_privateOptions = JsonConvert.DeserializeObject<List<AppOption>>(json);
}
}
return Task.FromResult(new AppOptions { Options = _privateOptions });
}
}
}
}
- Register the code list in
Program.cs
:
App/Program.cs
{
...
// Register your apps custom service implementations here.
services.AddTransient<IInstantiationProcessor, InstantiationProcessor>();
services.AddTransient<IAppOptionsProvider, YearsInWorkForceOptionsProvider>();
services.AddTransient<IAppOptionsProvider, IndustryOptions>();
...
}
- Add a text display component. Logic has been added to the component to hide it if “IKT (data/IT)” is not selected. The value
491
for the field is retrieved from theindustry.json
file. The ‘Submit’ button has also been moved to this page.
App/ui/layouts/arbeidsforhold.json
...
{
"id": "info-it-kompteanse",
"type": "Paragraph",
"textResourceBindings": {
"title": "arbeid.it-kompetanse"
},
"hidden": ["notContains", ["component", "Checkboxes-bransje"], "491"],
"dataModelBindings": {}
},
{
"id": "send-inn",
"type": "Button",
"textResourceBindings": {
"title": "button.send-inn"
}
},
...
- Add text resource:
App/config/texts/resource.nb.json
...
{
"id": "arbeid.it-kompetanse",
"value": "#### Vi ser at du besitter kompetanse vi trenger i kommunen. <br><br> [Se en oversikt over våre ledige stillinger her.](https://sogndal.easycruit.com/index.html)"
},
...