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"]
]

Uttrykket sjekker verdien til en tenkt komponent med ID “alder”. Dersom personen er 16 år eller mer, for eksempel 45 år gammel, returneres teksten:

Please consider applying for our open position!

For en person som er 62 år returneres teksten:

At 62, your are eligible for retirement

Og for en person som er 15 år (eller yngre, som f.eks. en 4-åring), returneres teksten:

At 4, you should stay in (pre)school

Bruksområder

Dynamiske uttrykk er foreløpig tilgjengelig for bruk i disse egenskapene, som definert i layout-filer.

KomponenterEgenskapForventet verdiFrontendBackend
Sider/layoutshiddenBoolsk
AllehiddenBoolsk
SkjemakomponenterrequiredBoolsk
SkjemakomponenterreadOnlyBoolsk
Repeterende grupperhiddenRowBoolsk
Repeterende grupperedit.addButtonBoolsk
Repeterende grupperedit.saveButtonBoolsk
Repeterende grupperedit.deleteButtonBoolsk
Repeterende grupperedit.alertOnDeleteBoolsk
Repeterende grupperedit.saveAndNextButtonBoolsk
AlletextResourceBindings.[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

Her endrer vi teksten til redigeringsknappen i en repeterende gruppe basert på om IsPrefill er satt til true i en gitt adresse i datamodellen. Dersom IsPrefill er true for en adresse, vil raden som viser frem den adressen ha en redigerings-knapp med teksten "View". Hvis IsPrefill er false blir teksten på knappen til den spesifikke raden "Edit".

Det er verdt å merke seg at dersom et oppslag på IsPrefill gir resultatet null(ikke funnet) så konverteres resultatet til false når det blir brukt i en if. Les mer detaljert om dette i seksjonene if og datatyper

{
   "id": "repeatingAddressGroup",
   "type": "Group",
   "children": [
      "field-id-one",
      "field-id-two",
   ],
   "dataModelBindings": {
      "group": "Citizen.FormerAdresses"
   },
   "maxCount": 10,
   "textResourceBindings": {
      "edit_button_open": [
      "if",
      [ "dataModel", "Citizen.FormerAdresses.IsPrefill" ],
      "View",
      "else",
      "Edit"
      ]
   }
}

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()”

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.

NB: Her beskrives noen implementasjonsdetaljer i app-frontend-react, og er kun relevant når du skal prøve et uttrykk i JavaScript-konsollet som er avhengig av en kjent posisjon i en repeterende gruppe. Dette kan endres i fremtiden, og slike endringer vil ikke påvirke uttrykk som man har definert i en applikasjon. Der hentes konteksten ut fra hvor uttrykket er definert i layout-filen.

Se for deg en repeterende gruppe for personer med to felt; navn og alder. Gitt dette uttrykket:

["component", "alder"]

Hva vil alderen være? Det vil kunne variere etter hvilken gruppe som evaluerer uttrykket. Har man har to grupper/rader vil både navn- og alder-komponentene finnes to ganger hver. Disse vil få ID-ene navn-0 og alder-0 (for den første raden) og navn-1 og alder-1 (for den andre raden). Du kan lete etter den nærmeste alder-komponenten (den som tilhører samme gruppe/rad som navn-komponenten) ved å spesifisere en mer nøyaktig ID i tilfeller der uttrykk evalueres i repeterende gruppe.

Tenk deg at følgende data er fyllt inn i en repeterende gruppe:

NavnKomponent-IDAlderKomponent-ID
Pernavn-024alder-0
Karinavn-136alder-1
Olanavn-218alder-2
evalExpression(["component", "alder"]); // Eksempel 1
evalExpression(["component", "alder"], "navn"); // Eksempel 2
evalExpression(["component", "alder"], "navn-0"); // Eksempel 3
evalExpression(["component", "alder"], "navn-1"); // Eksempel 4
  1. Denne vil finne “første og beste” alder-komponent, og finner dermed alder-0. Den returnerer derfor 24, Per sin alder.
  2. Denne prøver å evaluere uttrykket i kontekst av den første navn-komponenten den finner, som er navn-0. Den nærmeste alder-komponenten til navn-0 er alder-0, og dermed vår vi igjen 24, Per sin alder.
  3. Her prøver vi å lete i kontekst av navn-komponenten på første rad, og igjen finner vi 24, Per sin alder.
  4. I siste eksempel har vi spesifisert andre rad i den repeterende gruppen ved å evaluere i kontekst av navn-1. Her finner vi den nærmeste alder-komponenten alder-1, som er 36, Kari sin alder.

Funksjoner

Disse funksjonene er tilgjengelige for bruk i uttrykk:

FunksjonsnavnParametreReturverdiFrontendBackend
equalsStreng, StrengBoolsk
notEqualsStreng, StrengBoolsk
notBoolskBoolsk
greaterThanTall, TallBoolsk
greaterThanEqTall, TallBoolsk
lessThanTall, TallBoolsk
lessThanEqTall, TallBoolsk
concatIngen eller flere strengerStreng
andEn eller flere boolske verdierBoolsk
orEn eller flere boolske verdierBoolsk
ifSe detaljert beskrivelseSe detaljert beskrivelse
instanceContextStrengStreng
frontendSettingsStrengStreng
dataModelStrengStreng
componentStrengStreng

Detaljerte beskrivelser og eksempler

Disse to funksjonene sammenligner to strenger for å sjekke om de er like (equals) eller ulike (notEquals). Om du sender inn andre verdier enn strenger, blir verdiene konvertert og sammenlignet som strenger (les mer om konvertering her).

Eksempler:

{
  "id": "lastName",
  "type": "Input",
  ...
  "hidden": ["equals",
    ["dataModel", "My.Model.FirstName"],
    "John"
  ],
  "readOnly": ["notEquals",
    ["frontendSettings", "FormIsEditable"],
    true
  ]
}

notEquals er i prinsippet det samme som, og en snarvei til, ["not", ["equals", ...]].

Se også tips og triks under Streng eller mindre streng sammenligning?

Denne funksjonen tar inn en boolsk verdi eller noe som kan konverteres til en boolsk verdi, og returnerer den motsatte boolske verdien. Sann blir til usann, usann blir til sann.

Funksjonen kan være nyttig om du ønsker å snu et uttrykk. Istedenfor å tenke at du skal skrive et uttrykk som skjuler en komponent gitt noen forutsetninger, kan du pakke uttrykket inn i not og skrive uttrykket ut fra hva som skal til for å vise komponenten:

{
  "id": "lastName",
  "type": "Input",
  "hidden": ["not",
    ["or",
       ["dataModel", "ShowLastName"],
       ["frontendSettings", "ShowAllFields"]
    ]
  ]
}

Disse 4 funksjonene forventer to tall inn, og sammenligner om det første med det andre. Det vil si, for funksjonen greaterThan er uttrykket sant dersom det første tallet er større enn det andre.

FunksjonBeskrivelseSymbol
greaterThanEr det første tallet større enn det andre tallet?>
greaterThanEqEr det første tallet større enn eller lik det andre tallet?
lessThanEr det første tallet mindre enn det andre tallet?<
lessThanEqEr det første tallet mindre enn eller lik det andre tallet?

Dersom noen av argumentene til disse funksjonene er null blir resultatet false (uavhengig av om det er det første eller andre argumentet).

Eksempel som sjekker om alder er over (eller lik) 18:

["greaterThanEq", ["component", "alder"], 18]

Denne funksjonen tar inn 0 eller flere strenger som argumenter, og returnerer en streng hvor alle strengene i argumentene er slått sammen. Kalles funksjonen uten noen argumenter gis det en tom streng.

Legg merke til at funksjonen ikke automatisk legger til mellomrom eller komma når den slår sammen strenger. For å gi et mer lesbart resultat anbefales det å legge inn bindetegn hvor nødvendig:

["concat",
   "Gratulerer med ",
   ["component", "alder"],
   "-årsdagen!"
]

Uttrykket over gir teksten Gratulerer med 18-årsdagen! dersom verdien i alder-komponenten var 18.

I concat-funksjonen tolkes null-verdier som tomme strenger. Boolske verdier skrives ut som strengene "true" og "false".

Funksjonene and og or forventer 1 eller flere boolske verdier, og gir et resultat ut fra om henholdsvis alle eller minst en av verdiene var sanne (true).

FunksjonBeskrivelse
andEr alle argumentene sanne? (true)
orEr minst ett av argumentene sanne? (true)

Gir man null-verdier tolkes disse som usann (false). Eksempler på bruk finnes under Streng eller mindre streng sammenligning?

if-funksjonen kan brukes for å forgrene et uttrykk slik at returverdien styres av resultatet av et annet boolsk uttrykk. Funksjonen kan kalles på to forskjellige måter; med 2 eller 4 argumenter:

ArgumentAlternativ 1Alternativ 2
Første argumentBoolskBoolsk
Andre argumentVilkårlig typeVilkårlig type
Tredje argumentStrengen "else"
Fjerde argumentVilkårlig type

I alternativ 1 vil returverdien til funksjonen bli verdien gitt som andre argument dersom første argument er sant (true). Om ikke returneres verdien null.

I alternativ 2 vil returverdien til funksjonen bli verdien gitt som andre argument dersom første argument er sant (true). Om ikke returneres verdien gitt i fjerde argument. Man må alltid gi strengen "else" som tredje argument om man vil kalle funksjonen med 4 argumenter. Det tredje argumentet er bare til for å gjøre uttrykket mer lesbart, og har ingen funksjon ellers.

Om man ønsker flere betingelser og mulige returverdier kan man nøste flere kall til if inne i andre eller fjerde argument:

["if",
   ["greaterThan", ["component", "birthYear"], 1945],
   "Du ble født etter verdenskrigene",
"else",
  ["if",
     ["greaterThanEq", ["component", "birthYear"], 1939],
     "Du ble født under andre verdenskrig",
  "else",
     "Du ble født før andre verdenskrig"
  ]
]

Denne funksjonen gjør det mulig å hente ut informasjon om gjeldende instans. Følgende nøkler kan brukes fom første argument:

NøkkelVerdiEksempelverdi
instanceIdGjeldende instans-ID512345/48c31ffc-dcdd-416d-8bc7-194bec3b7bf0
instanceOwnerPartyIdGjeldende aktør-ID512345
instanceOwnerPartyTypeHva slags aktør eier instansen"org", "person", "selfIdentified" eller "unknown"
appIdDen aktive appen sin IDorg/app-name

Alle disse oppslagene vil gi verdien null om man jobber i en tiltandsløs kontekst. Om man gir andre nøkler enn de over, vil oppslaget resultere i en feilmelding. Denne oppførselen er unik blant oppslagsfunksjonene, og gjøres for å sikre at man ikke prøver å hente informasjon som finnes i instansen men som ikke (enda) er eksponert via en nøkkel her. Gi oss en tilbakemelding om du har ønsker om å hente ut instansdata som ikke er tilgjengelig i denne funksjonen.

Oppslaget gjøres i samme datakilde som er tilgjengelig for språk/tekster.

Dette oppslaget gjør det mulig å hente informasjon fra en datakilde som kan styres ulikt for hvert kjøretidsmiljø.

Oppslaget gjøres i samme datakilde som er tilgjengelig for språk/tekster, og oppsettet er beskrevet i detalj der.

Merk: Datakilden heter applicationSettings når brukt i språk/tekster, men verdiene må alltid lagres under nøkkelen FrontEndSettings i appsettings.{miljø}.json). Av den grunn har funksjonen fått navnet frontendSettings her, for å indikere at oppslag ikke kan gjøres i resten av appsettings.{miljø}.json.

Denne oppslagsfunksjonen gjør det mulig å hente verdier direkte fra gjeldende datamodell. Første og eneste argument må peke et sted i datamodellen, og bruker det samme punktum-separerte formatet som brukt i dataModelBindings. Ved bruk inne i repeterende grupper trenger man ikke bruke plassholdere for indekser til gruppen - uttrykket finner selv den relative plasseringen i kontekst av en repeterende gruppe.

Legg merke til at oppslag bare fungerer mot datatyper som allerede er støttet i uttrykkene. Dersom man slår opp et objekt eller en liste/array i datamodellen med dataModel-funksjonen får man alltid resultatet null. Denne funksjonaliteten kan endres, da det er planlagt støtte for objekter og lister i uttrykkene i fremtiden.

Eksempel på oppslag i repeterende gruppe:

[
   {
      "id": "ansatte",
      "type": "Group",
      "textResourceBindings": {
         "title": "Ansatte i selskapet"
      },
      "maxCount": 99999,
      "children": ["ansatt-navn", "ansatt-alder"],
      "dataModelBindings": {
         "group": "Ansatte"
      }
   },
   {
      "id": "ansatt-navn",
      "type": "Input",
      "textResourceBindings": {
         "title": "Fullt navn"
      },
      "dataModelBindings": {
         "simpleBinding": "Ansatte.Navn"
      },
      "hidden": ["lessThan",
        ["dataModel", "Ansatte.Alder"],
        18]
   },
   {
      "id": "ansatt-alder",
      "type": "Input",
      "textResourceBindings": {
         "title": "Alder"
      },
      "dataModelBindings": {
         "simpleBinding": "Ansatte.Alder"
      }
      "hidden": ["equals",
        ["dataModel", "Ansatte[0].Navn"],
        "Ola Nordmann"]
   }
]

Følgende kan observeres:

  1. Det første oppslaget (for å styre hidden på komponenten ansatt-navn) styres ut fra alderen til hver ansatt. Om den ansatte er under 18 år skjules ansatt-navn. Legg merke til at samme sti i datamodellen blir brukt som simpleBindingansatt-alder.
  2. Det andre oppslaget (for å styre hidden på komponenten ansatt-alder) bruker [0] på oppslaget i datamodellen. Dette fungerer også, men oppførselen er kanskje uventet; her skjules alle alder-komponenter dersom navnet på den første ansatte har navnet Ola Nordmann.

Oppslag direkte på komponent tilsvarer på mange måter et oppslag mot datamodell med dataModel. Et uttrykk som slår opp verdien til en komponent kommer til å lete etter komponenten og returnere verdien lagret på komponenten sin simpleBinding i datamodellen. For øyeblikket støttes ingen andre verdier enn den lagret mot simpleBinding (om andre verdier ønskes må man gå direkte mot dataModel).

Oppslag mot en komponent vil derimot returnere null dersom komponenten man slår opp verdien til er skjult (selv om komponenten ellers har tilknyttet data i datamodellen). Dette gjør det til en viss grad mulig å styre visning av en komponent basert på om en annen komponent er vist eller ikke. Dersom komponenten ble funnet på en helt annen (men skjult) side gir også oppslaget verdien null selv om datamodellen har en verdi tilknyttet komponenten.

I likhet med dataModel vil oppslag mot en komponent-id forsøke å finne komponenten i nærheten av uttrykket i kontekst av repeterende grupper. Det vil først søkes etter komponenten i gjeldende rad, før det letes oppover i sidestrukturen.

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:

StrengverdiKan erstatteEksempler
Heltall med eller uten negativt fortegnTall3, -8, 71254
Desimaltall med eller uten negativt fortegnTall3.14, -33.0, 123.123
true eller false med små eller store bokstaverBoolsktrue, True, FALSE
null med små eller store bokstaverNullnull, 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 og 0 fungerer som henholdsvis true og false
  • Strengene "1" og "0" fungerer likt som tallene (og blir henholdsvis true og false)
  • Strengene "true" og "false" konverteres også til en boolsk verdi
  • Verdien null fungerer likt som false

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:

  1. "hidden": ["dataModel", "hideName"]
  2. "hidden": ["equals", ["dataModel", "hideName"], true]
  3. "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:

  1. 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.
  2. 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"], ""]
]