Dynamic expressions
Overview of dynamic expressions defined in JSON
On this page:
⚠️ Dynamic behaviour is an area under active development. This functionality is not configurable directly in Altinn Studio yet, and must be configured manually in the JSON files.
Introduksjon
Dynamikk via uttrykk gjør det mulig å definere enkel dynamisk oppførsel i en Altinn 3 app, som for eksempel ved å definere om et skjemafelt skal vises eller skjules, om feltet skal være påkrevd eller skrivebeskyttet.
Uttrykkene er tilgjengelige i alle Altinn 3-apper som bruker frontend-versjon 3.54.0 eller nyere. Bruker man denne versjonen (eller siste hovedversjon) har man mulighet til å benytte dynamiske uttrykk til flere bruksområder.
Fra versjon 7.2.0
av nuget-pakkene er også uttrykkene støttet i backend.
Det gjør at serveren vil kunne evaluere uttrykkene og fjerne data ved innsending som potensielt er lagret
i datamodellen og er knyttet til felter/komponenter som i ettertid er skjult.
Merk at dette bare gjelder data i datamodellen som er knyttet til skjulte komponenter - data i datamodellen som ikke
er knyttet til komponenter (og dermed implisitt skjult for brukeren) vil ikke fjernes automatisk.
Det gjør det også mulig å unnlate å sende inn data som ellers er tilknyttet påkrevde felter - dersom disse påkrevde feltene er skjult i skjemaet ved hjelp av dynamiske uttrykk. Dette gjelder også ved innsending direkte fra API.
NB: Automatisk fjerning av skjult data må foreløpig aktiveres manuelt (opt-in) ved at man legger til følgende
linje i App/appsettings.json
etter at man har oppgradert nuget-pakkene
til 7.2.0
eller nyere:
"AppSettings": {
"OpenIdWellKnownEndpoint": "http://localhost:5101/authentication/api/v1/openid/",
"RuntimeCookieName": "AltinnStudioRuntime",
"RegisterEventsWithEventsComponent": false,
"RemoveHiddenDataPreview": true
},
Oppbygging og syntaks
Uttrykkene er bygget opp som et slags mini-programmeringsspråk, hvor alt er definert i JSON. Selve uttrykkene er alltid en liste (array) med verdier, hvor den første verdien i hver liste alltid er et funksjonsnavn. Resten av verdiene sendes som inndata/argumenter til funksjonen.
["equals", "foo", "bar"]
I eksempelet over blir strengene “foo” og “bar” sammenlignet. De er ulike, så resultatet av dette uttrykket blir en boolsk verdi; false.
Denne funksjonen, equals, forventer å få inn to strenger som inndata/argumenter. Det er også mulig å gi den andre uttrykk. Gjør man dette vil uttrykket bli tolket slik at de innerste funksjonene blir kjørt først, og de ytterste kjørt sist.
["equals", ["component", "firstName"], "John"]
I dette eksempelet blir det innerste uttrykket/funksjonskallet ["component", "firstName"]
kjørt først. Om verdien til
komponenten “firstName” er lik strengen “John”, gir funksjonen resultatet den boolske verdien “true”.
Dersom man da bruker dette uttrykket for hidden
-egenskapen til en komponent, vil komponenten bli skjult dersom man
skriver inn “John” i “firstName”-komponenten et annet sted i applikasjonen:
{
"id": "lastName",
"type": "Input",
...
"hidden": ["equals", ["component", "firstName"], "John"]
}
Det er ingen begrensninger rundt hvor store/dype uttrykkene kan være. Som en øvelse, se om du klarer å lese hva dette uttrykket gjør, og hvilke mulige verdier det kan returnere:
[
"if",
["greaterThanEq", ["component", "age"], 16],
[
"if",
["lessThan", ["component", "age"], 62],
"Please consider applying for our open position!",
"else",
["concat",
"At ", ["component", "age"], ", you are eligible for retirement"]
],
"else",
["concat",
"At ", ["component", "age"], ", you should stay in (pre)school"]
]
Bruksområder
Dynamiske uttrykk er foreløpig tilgjengelig for bruk i disse egenskapene, som definert i layout-filer.
Komponenter | Egenskap | Forventet verdi | Frontend | Backend |
---|---|---|---|---|
Sider/layouts | hidden | Boolsk | ✅ | ✅ |
Alle | hidden | Boolsk | ✅ | ✅ |
Skjemakomponenter | required | Boolsk | ✅ | ✅ |
Skjemakomponenter | readOnly | Boolsk | ✅ | ❌ |
Repeterende grupper | hiddenRow | Boolsk | ✅ | ❌ |
Repeterende grupper | edit.addButton | Boolsk | ✅ | ❌ |
Repeterende grupper | edit.saveButton | Boolsk | ✅ | ❌ |
Repeterende grupper | edit.deleteButton | Boolsk | ✅ | ❌ |
Repeterende grupper | edit.alertOnDelete | Boolsk | ✅ | ❌ |
Repeterende grupper | edit.saveAndNextButton | Boolsk | ✅ | ❌ |
Alle | textResourceBindings.[textResourceBinding] * | Streng | ✅ | ❌ |
* = Hvilke verdier man kan overstyre med textResourceBindings varierer fra komponent til komponent, men vil fungere på alle steder der det brukes. TextResourceBindings for repeterende grupper finner du mer informasjon om her
Testing, feilsøking og utvikling av uttrykk
Når man skal skrive et uttrykk er det greit å vite noenlunde hva resultatet kommer til å bli, og om uttrykket er gyldig. Ugyldige uttrykk gir en advarsel i JavaScript-konsollet i nettleseren når siden lastes, så det kan være lurt å ha dette konsollet åpent når man utvikler en applikasjon og tester uttrykkene lokalt.
Det er også mulig å teste ut kjøring av et uttrykk rett i nettleserens JavaScript-konsoll. Det gjøres ved å bruke
funksjonen evalExpression()
. Som første parameter tar den inn et hvilket som helst uttrykk, og resultatet skrives
tilbake til konsollet:

Eksempelkjøring av evalExpression()
Uttrykk vil også kunne oppføre seg annerledes alt etter hvilken komponent de evalueres i nærheten av. Som et valgfritt andre parameter kan du også sende inn ID-en til en komponent som skal brukes som kontekst når uttrykket evalueres. Hvis du er usikker på hvilke komponenter og IDer som er tilgjengelige på siden du ser på i applikasjonen, kan du prøve å sende inn en tom streng eller ugyldig komponent-ID som andre parameter, så vil du få tips til hvilke ID-er du kan bruke.
Funksjoner
Disse funksjonene er tilgjengelige for bruk i uttrykk:
Funksjonsnavn | Parametre | Returverdi | Frontend | Backend |
---|---|---|---|---|
equals | Streng, Streng | Boolsk | ✅ | ✅ |
notEquals | Streng, Streng | Boolsk | ✅ | ✅ |
not | Boolsk | Boolsk | ✅ | ✅ |
greaterThan | Tall, Tall | Boolsk | ✅ | ✅ |
greaterThanEq | Tall, Tall | Boolsk | ✅ | ✅ |
lessThan | Tall, Tall | Boolsk | ✅ | ✅ |
lessThanEq | Tall, Tall | Boolsk | ✅ | ✅ |
concat | Ingen eller flere strenger | Streng | ✅ | ✅ |
and | En eller flere boolske verdier | Boolsk | ✅ | ✅ |
or | En eller flere boolske verdier | Boolsk | ✅ | ✅ |
if | Se detaljert beskrivelse | Se detaljert beskrivelse | ✅ | ✅ |
instanceContext | Streng | Streng | ✅ | ✅ |
frontendSettings | Streng | Streng | ✅ | ✅ |
dataModel | Streng | Streng | ✅ | ✅ |
component | Streng | Streng | ✅ | ✅ |
Detaljerte beskrivelser og eksempler
Datatyper
Funksjoner i uttrykkene har en forventning om at argumentene som blir sendt inn har en spefikk type. Dersom et argument
blir sendt inn har en annen type enn forventet, blir verdien forsøkt konvertert til riktig type. Som et eksempel
forventer funksjonen equals
to strenger, men om du sender inn den boolske verdien true
som det ene eller andre
argumentet fungerer det også fint, siden den boolske verdien true
blir konvertert til strengen "true"
.
["equals", true, "true"]
Uttrykket over fungerer, og gir true
som resultat (fordi true
og "true"
sammenlignes som samme verdi ved at
true
konverteres til "true"
før sammenligningen). Dette gjør også at du kan kalle en funksjon som returnerer en
datatype og f.eks. sammenligne med en helt annen datatype. Les mer om hvilke datatyper som kan konverteres til hva
under.
Alle funksjoner som forventer en spesifikk datatype som argument vil også kunne fungere om man sender
inn null
, men noen steder vil en null
-verdi gi en feilmelding - for eksempel om man prøver å slå opp i
datamodellen med ["dataModel", null]
. I concat
-funksjonen vil derimot en null
-verdi bli tolket som en tom streng.
Strenger
Strenger inneholder vilkårlig tekst, og er en bred datatype som tall og boolske verdier kan konverteres til.
Noen strenger kan også konverteres til andre datatyper:
Strengverdi | Kan erstatte | Eksempler |
---|---|---|
Heltall med eller uten negativt fortegn | Tall | 3 , -8 , 71254 |
Desimaltall med eller uten negativt fortegn | Tall | 3.14 , -33.0 , 123.123 |
true eller false med små eller store bokstaver | Boolsk | true , True , FALSE |
null med små eller store bokstaver | Null | null , Null , NULL |
Alle andre strenger enn de i tabellen over vil gi feilmelding om de blir forsøkt konvertert til andre typer.
Tall
Tallverdier gjelder positive og negative heltall og desimaltall. Noen strenger blir også konvertert automatisk til en tallverdi, som vist i tabellen til strenger over. For at konvertering av en streng til et tall skal fungere, må strengen oppfylle følgende:
- Strengen inneholder bare et tall, ingen annen tekst foran/bak tallet
- Negativt fortegn (
-
) kan brukes, men positivt fortegn (+
) støttes ikke. - Desimaltall må representeres med punktum, ikke komma.
- Tusenskilletegn eller annen tallformattering støttes ikke.
Alle andre strenger vil gi en feilmelding om de blir forsøkt konvertert til et tall. Forsøker man å konvertere en boolsk verdi til et tall, gir det også en feilmelding.
Funksjoner som forventer å få inn et tall kan også få inn null
. Se mer om hvilken effekt det har under
beskrivelsen til hver funksjon.
Boolske verdier
Boolske verdier omfatter true
(sann) og false
(usann). Når man kaller en funksjon som forventer å få inn en boolsk
verdi, kan man også sende inn enkelte andre typer, som blir konvertert til en boolsk verdi:
- Tallene
1
og0
fungerer som henholdsvistrue
ogfalse
- Strengene
"1"
og"0"
fungerer likt som tallene (og blir henholdsvistrue
ogfalse
) - Strengene
"true"
og"false"
konverteres også til en boolsk verdi - Verdien
null
fungerer likt somfalse
Alle andre verdier gir en feilmelding om de blir sendt til en funksjon som forventer en boolsk verdi. Legg merke til
at disse reglene er litt forskjellige fra reglene til strenger. Det er dermed forskjell på hvilke verdier
som kan tolkes som en boolsk verdi for en funksjon som forventer et boolsk argument - og hvilke verdier som er like
en boolsk verdi. Funksjonen equals
sammenligner verdier som strenger, og dermed vil tallet 1
og
strengen "1"
sammenlignes som like, men den vil ikke gjenkjenne 1
og true
som like verdier.
Det kan kanskje se ut som følgende uttrykk er like:
"hidden": ["dataModel", "hideName"]
"hidden": ["equals", ["dataModel", "hideName"], true]
"hidden": ["if", ["dataModel", "hideName"], true, "else", false]
Hvis verdien (her gitt fra oppslaget ["dataModel", "hideName"]
) er true
eller "true"
vil
komponenten skjules, men dersom verdien er 1
eller "1"
vil komponenten bare skjules med uttrykkene i alternativ
1 og 3. Dette fordi resultatet i uttrykket for hidden
konverteres til en boolsk verdi, og
if
forventer en boolsk verdi som første argument. Derimot vil equals
sammenligne verdiene som strenger,
og "1"
er ikke lik "true"
.
Se også tips og triks under Streng eller mindre streng sammenligning?
Null
De fleste steder hvor man forventer å få inn en streng, tall eller
boolske verdier skal også tåle en null
-verdi. Null-verdier indikerer at en spesifikk verdi
mangler, og det er forskjell på f.eks. en null
-verdi, en tom streng og tallet 0
.
Dersom man gjør et oppslag i en funksjon som dataModel
, og verdien man leter etter ikke finnes/er satt, vil som regel
null
bli resultatet.
Tips og triks
Vise/skjule hele sider
Uttrykk kan brukes til å vise/skjule hele sider. I eksempelet under vil hele siden skjules dersom en komponent (på en av de andre sidene) har verdien no eller ikke er satt.
{
"$schema": "https://altinncdn.no/schemas/json/layout/layout.schema.v1.json",
"data": {
"hidden": ["or",
["equals", ["component", "hasComplaints"], "no"],
["equals", ["component", "hasComplaints"], null]
],
"layout": [
...
]
}
}
Dette kan sees på som et alternativ til sporvalg-funksjonaliteten, men i motsetning til
sporvalg gjøres utregningen av disse uttrykkene i både frontend og backend, dermed er det ikke nødvendig å legge
til "triggers": ["calculatePageOrder"]
for å få funksjonaliteten til å fungere.
Dersom siden man stod på blir skjult, vil applikasjonen automatisk gå videre til neste tilgjengelige side i side-rekkefølgen. Om alle de neste sidene er skjult, vises den første mulige siden i rekkefølgen istedenfor.
Streng eller mindre streng sammenligning?
Måten uttrykkene kjøres på gjør at de kan virke litt strenge (ved at f.eks. 0
og null
er ulike verdier når man
sammenligner med equals
). Det er et designvalg gjort i Altinn av to grunner:
- Strenge regler er tydelige regler. Uttrykkene vil heller gi en feilmelding om noe ikke er som forventet, enn å la deg lure på hvorfor det ble slikt det ble.
- Hvis uttrykkene behandler mange ulike verdier som like, fratar vi deg muligheten til å skille mellom dem om du skulle ønske det.
Om man ønsker mindre streng sammenligning, kan man f.eks. konstruere et uttrykk som bruker or
-funksjonen
til å gjenkjenne flere forskjellige verdier:
["or",
["equals", ["dataModel", "My.Path"], 0],
["equals", ["dataModel", "My.Path"], false],
["equals", ["dataModel", "My.Path"], null],
["equals", ["dataModel", "My.Path"], ""]
]
Husk også at konvertering til boolsk verdi tillater flere alternativer enn strenger
(som equals
forventer). Siden funksjonen or
forventer boolske verdier som argumenter, og verdiene
0
, false
og null
allerede tillates som boolske verdier vil følgende fungere likt som uttrykket over:
["or",
["dataModel", "My.Path"],
["equals", ["dataModel", "My.Path"], ""]
]