Show all Hide all

Displays one or more columns of controls, each with its own field information. The number of rows can either be fixed or rows can be created and deleted dynamically.

The fields can depend on other fields on the same row, previous row and on fields outside the multirow control. Use the syntax {fieldname} to refer to a field on the same row, {fieldname(-1)} to refer to a field on the previous row or {../fieldname} to refer to a field outside the multirow control. The {fieldname} and {../fieldname} syntaxes are supported in SQL, default value and visibility fields, while {fieldname(-1)} currently is only supported in default value.

Observe that default value dependencies always updates all rows in the control when the value of the referred control changes. Previous row dependencies will cascade through all rows when the value of a referred control is changed.

Changing the number of columns or meta data for columns during updates of the multirow control is not allowed.

Start value: Used in SQL to retreive row values (@id)
Return value:

Control container: NewEdit

Supported in: NewEdit

Return values

A multirow will either be saved as a ¤-separated string or a temporary table, depending on the setting Use temp table. When consumed as a field dependency it will always be a string.


The multirow will be represented as a series of values separated by the ¤ character, with no extra indication of when one row ends and a new row begins. The string is usually parsed by the SoftadminApi.Multirow_Parse procedure.

Temporary table

A temporary table with columns corresponding to the fields and rows in the control is created. The table will also contain the column RowPosition containing zero-indexed row numbers. An additional parameter @xxxTableName containing the name of the temporary table is passed to the InsertUpdate-procedure.


SQL Call: Retrieve fields to edit (mandatory)

SQL-statement that returns the columns and rows to be displayed in multi row component.

May modify database: No


@id string
Indicates which database record to collect rows from.

Resultset: Dynamic field information (optional)

Specify extra field information for the columns in the multirow.
Repeat mode: repeated zero or more times
Row count: zero or more rows


<xxx> optional string
Set property <xxx> for the field specified in adminfieldname. If set to null the value will not be applied.
AdminFieldName mandatory string
The name of the field to apply the information to. The presence of this column indicates that the resultset specifies field information.
ButtonJavaScript<xxx> optional string
Inserts a button next to the control that is used to execute the JavaScript supplied here. <xxx> is an arbitrary text that can be empty if only one button is required.
ButtonJavaScript<xxx>_Label optional string
The label for the JavaScript button <xxx>.
CellAlignment optional string
Specifies the alignment of the text in the field.
Possible value Description
Center Center aligned.
Left Left aligned.
Right Right aligned.
ColumnTooltip optional string
Sets the tooltip on the column title. Only supported by the Grid component.
DefaultValue optional string
The default value for the control or if prefixed by 'SQL:' the sql to run to determine the default value.
Description optional string
The description for the field.
EnabledJavaScript optional string
Javascript that controls the enabled status of the field. The control is only enabled if the expression specified here evaluates to true. The expression is evaluated every time the value of a dependent control is changed. This is only available to control types for which the enabled javascript field is visible in the user interface.
FieldGroupId optional int
The field group to use.
FieldInfoId optional int
ID of field information to base the dynamic field on. All properties not explicitly overridden by dynamic field information will be copied from this field. The referenced field must be found in the menu item's field tables.
FieldLabel optional string
If present the field label is used as the heading for fields instead of the field name.
FieldType optional string
The name of the control type to use.
Height optional int
The height of the control.
IgnoreOnSave optional bit
Do not pass the field value to the insert/update procedure.
InfoSqlLayout optional string
Where the label is shown in relation to the contents in InfoSQL.
Possible value Description
LabelAbove Full width, label above.
NoLabel Full width, no label.
Standard Label to the left.
NullChoice optional bit
Specifies whether the control allows null values.
NumberOfDecimals optional int
The number of decimals to display for numeric values.
OnChangeJavaScript optional string
Javascript run when the value of the control has changed.
OutputFormat optional string
Special formatting to be applied when the field is displayed.
Possible value Description
Placeholder optional string
Text shown when the field is empty.
Sql optional string
The SQL that determines the control's behavior. (Refer to control documentation for more information)
ThousandDelimiter optional string
The thousand grouping delimiter for numeric values.
Width optional int
The width of the control.
VisibleJavaScript optional string
JavaScript that controls the visibility of the field. The control is only visible if the expression specified here evaluates to true. The expression is evaluated every time the value of a dependent control is changed.

Resultset: Rows to edit

Resultset that fills the multi row control with data. Each row in the resultset corresponds to a row in the control. Column names determines which field information to use. The returned values will be the start value of the controls in the multirow, but null values in the resultset will cause the default value to be computed and displayed in the cell. The field names rowid, rowids and controlchanged are reserved by the multirow control and cannot be used as column names.
Repeat mode: repeated exactly once
Row count: zero or more rows


<xxx> optional string
Column to edit
row_CanDelete optional bit
This special column is used to indicate which rows can be deleted. This column will not be visible in the multirow control.
Default: By default all rows can be deleted if delete buttons are enabled in the properties for the multirow control.
Possible value Description
0 The row cannot be deleted, i.e. the delete row button is disabled.
1 The row can be deleted.
row_CanUpdate optional bit
This special column is used to indicate which rows can be edited by the user. This column will not be visible in the multirow control.
Default: By default all rows can be edited.
Possible value Description
0 The row cannot be directly edited by the user, i.e. all controls on the row are disabled.
1 The row can be edited by users.

Default value

SQL Call: Default value

Retrieves the default value for the control.

May modify database: No

Resultset: Default value

Repeat mode: repeated exactly once
Row count: exactly one row


<column with ordinal 1> mandatory string
The default value


SQL Call: Validation

This call is only made if there is a field validation set for the field info and the field has any content.

Live Validation

Performs field validation when the user leaves the field or one of its dependencies is changed, initial values set by default value and initial values in edit-mode are not validated.

Save Validation

When saving the validation runs server side if the field value has changed. A field value is considered changed if in new mode the value is anything other than NULL. In edit mode it is considered changed if it has a value that was not returned by the GetEditFields procedure.

May modify database: No


@Value string
The value of the field, the procedure will not be called if value is NULL.

Resultset: Validation messages (optional)

Repeat mode: repeated zero or one time
Row count: zero or one row


Error optional string
Error message to display. Blocks the user from saving.
Info optional string
Informative message to display. Does not block saving.


Multirow procedure

Example multirow procedure. Field info for the fields that make up the multirow is set with regular field info as you would with any other field.

CREATE PROCEDURE Example.MultiRowTable_MultiRow
	@Id		int = NULL

		-- Used when updating, hidden using field info of type "hidden"
		-- Columns to edit
		Example.MultiRowTable MRT
		MRT.OwnerObjectId = @Id


Multirow InsertUpdate example

Example of how to handle data from a multirow in an InsertUpdate procedure. Note that we assume the name of the temp table in order to avoid using a dynamic query.

A CTE is used in the MERGE statement to ensure that we only handle relevant records, ie. we don't want to delete records not found in the source belonging to other RowIds.

CREATE PROCEDURE Example.MultiRowTable_InsertUpdate
	@Id							int = NULL,
	@ExampleMultiRow			int = NULL,
	@ExampleMultiRowTableName	sysname = NULL	-- dummy, the temp table is assumed to be named #ExampleMultiRow

	-- We operate on a CTE to avoid doing anything to rows belonging to other OwnerObjectIds
		-- T as in Target, the table into which we want to MERGE data
		T AS (
				Example.MultiRowTable MRT
				MRT.OwnerObjectId = @Id
		-- S as in Source, the source data for our MERGE
		) S ON
			S.MultiRowTableId = T.MultiRowTableId
	-- If no match was found in the target for a row in the source 
	-- we want to add that row since it is new
	-- If a match was found between source and target 
	-- we want to update the target row with new data
			MultiRowExampleColumnA	= S.MultiRowExampleColumnA,
			MultiRowExampleColumnB	= S.MultiRowExampleColumnB,
			MultiRowExampleColumnC	= S.MultiRowExampleColumnC
	-- If no match was found in the source for a row in the target 
	-- we want to delete that row since it has been removed and is no longer valid


Best practice

Always use an explicit ORDER BY

For stable and predictable behaviour, always use an explicit ORDER BY clause.

Name of stored procedure

The stored procedure should be named "<Schema>.<TableMultiRowGetsRowsFrom>_MultiRow".