v4
Overview of breaking changes introduced in v4 of app frontend.
App frontend v4 brings with it some new features and breaking changes. This document aims to give an overview of the changes and how they may affect your app. As always, with a new major version, we recommend that you test your app thoroughly before deploying to production.
Requires backend version 8.0.0
App frontend v4 requires at least version 8.0.0 of the Altinn.App.Core
and Altinn.App.Api
nuget packages.
See the overview of changes in backend v8 for more information on how to upgrade.
Using layout sets is now required
Layout sets is a way to support multiple forms in a single application.
This entails a slightly different folder structure in the ui
folder of your app, as well as a new layout-sets.json
file.
This used to be optional, but as of v4 it is required, even for apps with only a single data step.
See the documentation on layout sets for more information.
Defining a custom receipt is now done with a layout set
v4.0.0-rc3
. It was not present in v4.0.0-rc1
or v4.0.0-rc2
. In these previous versions,
a custom receipt was not supported.A custom receipt view can now be created in the same way as all other form pages.
To create a custom receipt view, you create a new layout set. This layout set works exactly like
all other page types. Within the layout set, you can create a layouts
folder and define all the pages you want to
include in the receipt view here (Yes, the receipt view supports multiple pages!). Inside the layout set, you must also create
a Settings.json
, where you can define the order of the pages in the receipt view.
For the app to understand that this layout set should be used as a receipt view, you must refer to the name of the layout set
in layout-sets.json
. Add a new layout set with id
that refers to the name of your layout set, and add
the key value "CustomReceipt"
in the tasks
array of the layout set. In addition, you can specify which data model
should be available in the receipt view by adding the key dataType
with the name of the data model you want to support.
Here is a complete example where we have a layout set named custom-receipt that will be used as a receipt view:
|- App/
|- ui/
|- layout-sets.json
|- custom-receipt/
|- layouts/
|- page1.json
|- page2.json
|- Settings.json
App/ui/layout-sets.json
{
"$schema": "https://altinncdn.no/toolkits/altinn-app-frontend/4/schemas/json/layout/layout-sets.schema.v1.json",
"sets": [
{
"id": "custom-receipt",
"dataType": "fields",
"tasks": ["CustomReceipt"]
}
]
}
App/ui/custom-receipt/Settings.json
{
"$schema": "https://altinncdn.no/toolkits/altinn-app-frontend/4/schemas/json/layout/layoutSettings.schema.v1.json",
"pages": {
"order": ["page1", "page2"]
}
}
AddressComponent has been renamed to Address
v4.0.0-rc2
. It was not present in v4.0.0-rc1
, so the component was still called
AddressComponent
in that release.In the layout files, the AddressComponent
component has been renamed to Address
. Our upgrade tool will rename
this for you automatically, but if you are migrating manually you will have to do this yourself.
Language and text resource changes
The language system that handles internal texts and app-specific text resources has been rewritten and improved. It should work mostly the same as before, but there are a few subtle changes that may affect your app:
- Previously, when referring to a path in the data model which resulted in a null value, the full path would be shown instead for most components. However, in options from repeating groups, it would instead show an empty string in place of the null value. This has been changed so that the full path is shown in all cases instead.
- To alleviate the problem of referring to null values, a new
defaultValue
property has been added to the text resources that, if set, will be shown instead of the data model path. See the documentation on text resources for more information. - Variables in text are now supported for items in nested repeating groups. Previously, only items in top-level repeating groups were supported in text resource variables.
- Using
dataModel.default
as the data source in text resources is no longer recommended. Instead, refer to the specific data type like this:dataModel.myDataModel
. The frontend will now automatically retrieve the data model it needs when a text resource is displayed anywhere on the page, butdataModel.default
will only work when rendering a form, as it will use the default data model for that form. We’re planning to add support for multiple data models in one form in the future, and at that point there will be no concept of a default data model.
Most users will be prompted for party each time
In the Altinn profile it was possible to change a setting to ’not be prompted for party each time’. This setting was mistakenly never read by app-frontend, so we failed to respect it. The default setting in Altinn profile is to be prompted for a party each time, so in v4 we changed the default behaviour of app-frontend to match the setting in Altinn profile. This means that most users will be prompted for party each time they start an app, unless they have changed the setting in Altinn profile.
The setting can be found under Advanced settings in the Altinn profile:
Unless the user changes this setting, they will be prompted with the following page each time they start a new instance:
Tracks are no longer supported
Showing and hiding pages using tracks (calculate page order) is no longer supported.
This also means that the trigger calculatePageOrder
no longer has any effect and should be removed from any components where it is used.
Instead, you should use dynamic expressions on the hidden
property of a layout page to determine whether pages should be visible or hidden.
To opt-in for an automatic AI-generated Pull Request to help you migrate from the old tracks feature, see the Opt-in to Altinn AI for tracks migration.
See the documentation on dynamic expressions for more information.
Data model schema validation works for more data models
The form data gets validated against the data model schema to show validation messages to the user filling out the form. There was a bug in v3 that caused this validation to not happen at all for certain data model structures. This has been now been fixed, but is a breaking change since if you previously did not get any schema validation errors, you may suddenly see them now. If this was the case you should test your app to make sure validation works as expected.
Support for number
, integer
and boolean
and other data types
One of the new features is full support for non-string data types in the data model. This means that you can now have
data model fields of type number
, boolean
, and bind them to components. For example, if you bind
a Checkboxes
component to a boolean
field, and provide an options list with the strings "true"
and "false"
, the
frontend will convert the strings to booleans.
If you bind an Input
component to a number
field, the frontend will convert the string to a number while the user
is typing. For the best possible user experience, set up number formatting
on the Input
component.
Note: If you have set up a RuleHandler.js
file in your app, you may need to update it to handle the new data types.
In cases where the RuleConfiguration.json
file specified a path that pointed to a number
or boolean
field,
the RuleHandler.js
file would previously receive a string value. This is no longer the case, and
code in RuleHandler.js
should be updated accordingly.
Note: In addition to all of this, the app frontend now properly supports objects and null
values. This should
not affect most apps, but it might be of interest when writing data processor code on the backend. If your data model
initializes an object, even if empty, the app-frontend will now preserve that object in later communication with the
backend. Previously, app-frontend would remove empty objects from the data model, leading to data processors
having to re-initialize the object on the backend every time. Please note that app-frontend does not initialize
objects for you the first time, so you still need to do that in your data model or data processor code.
The saveWhileTyping
property now only accepts numbers
The saveWhileTyping
property on the Input
component and other Input-like components used to accept a boolean value
for turning off saving while typing. In v4, saving while typing is always enabled, but it is still possible to
delay saving by setting saveWhileTyping
to a number larger than 400 (our default debounce time in milliseconds).
When delaying saving, we may still save the data to the backend before that time, for example when the user navigates
away from the field and starts typing in a new field (with a lower, or default saveWhileTyping
value).
If your app relied on disabling saveWhileTyping
to ensure your custom data processor was not called too often
(as we’ve often seen done when a change in one field triggers an API call), you should consider making the expensive
action in your data processor a custom action instead, via adding
a CustomButton component nearby the field. This way the user controls
when the action is triggered, not our automatic saving functionality.
Components will not show up if they contain configuration errors
Because of the support for other data types, we now have to be more strict about the configuration of components, as the frontend has to make sure it is able to look up the data model value expected for a component in order to save data into it. Previously the app-frontend would assume data model bindings were correct, and in combination with the backend, invalid bindings would result in data being lost.
To be on the safer side, components will now be replaced with an error message if they contain configuration errors, including invalid data model bindings. These error messages will only appear in development mode (i.e. in a test environment, or when running locally). In production, it will appear as if invalid components are hidden.
You should thoroughly test your app to make sure that components display correctly and that all data model bindings are correct. Testing this should include opening repeating groups and triggering conditions to unhide hidden components.
If you get an error message for an invalid binding you disagree with, please check that the data model *.schema.json
file is up-to-date with the latest changes to the data model. Do not hesitate to contact us if you need help with this.
The group component has been split into multiple components
The different methods of configuring the Group
component have been split into separate components.
Title and description changes for Groups
The title
attribute in textResourceBindings
for the RepeatingGroup
component previously only applied
to the title shown above each row in the summary view of the repeating group. This attribute is now only used as the
title for the repeating group in the form view. This means that the title will now be shown above the repeating group in
the form view if it has been set.
The summaryTitle
attribute in textResourceBindings
for the RepeatingGroup
component will override the title
, and
is used for displaying the title above each row in the summary view of the repeating group.
The body
attribute in textResourceBindings
for the Group
component and RepeatingGroup
component is now called
description
in order to be more consistent with the rest of the components.
Validation triggers have been replaced
The concept of triggering validations has been removed in favor of keeping the validations in sync with the data model. Instead of controlling when validations are triggered, you now control when validations are displayed to the user. This functions more or less the same as before, but the configuration has been changed.
This change also has the advantage that the need for *FIXED*
validations no longer exists, as a
IFormDataValidator
in your custom backend code can now control when it should run, and when it runs all its validation
messages are treated as one group. This means that if you have a validation that checks the value of another field,
or multiple fields at once, the validation message will disappear in frontend when the validation message is no longer
added to the list of validation messages in the backend - even if another component than the validation message target
was the one that changed.
AttachmentList config changes
The AttachmentList
component has undergone updates in v4 to address two key issues:
1. Enhanced Attachment Display
Previously, the AttachmentList could only show either PDFs or other attachments. In version 4, it has been changed to show both PDFs and other attachments simultaneously.
Changes to configurations:
The includePDF
property has been removed. It was previously used to display generated PDFs,
but when set to true
, it excluded all other attachments. Now the AttachmentList can display both PDFs and other attachments by using one of the following configurations:
"dataTypeIds": ["include-all"]
This is a new property and will display all data types including PDFs."dataTypeIds": ["fileUpload-changename", "ref-data-as-pdf"]
This will display both PDFs and other attachments that are specified, in this case the data typefileUpload-changename
.
2. Displaying Attachments from other process tasks
Previously, the AttachmentList was limited to displaying attachments solely from the current process task, which was not optimal. This limitation was particularly noticeable when the component was used in the receipt page, which is displayed only after the last process task.
Changes to configurations:
Now, by default, the AttachmentList will display attachments from other process tasks as well.
If dataTypeIds
is undefined or an empty array, it will show all attachments (excluding PDFs) from different process tasks.
Alternatively, configuring dataTypeIds
as ["current-task"]
will yield the same behavior but for the current task only.