Control: Multirow

 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: A temporary table with columns corresponding to the fields in the control. If reordering is enabled, then the additional column RowPosition is included in the temporary table indicating the position of each row.

Control container: NewEdit

Supported in: NewEdit

SQL

SQL Call: Retrieve fields to edit (mandatory)

SQL-statement that returns the columns and rows to be displayed in multi row component.
Supports custom errors: No
May modify database: No

Parameters:

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

Resultset: Dynamic field information

Specify extra field information for the columns in the multirow.
Repeat mode:
Row count:

Columns:

<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
Hyperlink
MailToLink
PhoneLink
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

Columns:

<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.
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.
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.
Supports custom errors: No
May modify database: No

Resultset: Default value

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

Columns:

<column with ordinal 1> mandatory string
The default value

Validation

SQL Call: Validation

Performs field validation when the user leaves the field or one of its dependencies is changed. This call is only made if there is a field validation of type SQL set for the field info.
Supports custom errors: No
May modify database: No

Parameters:

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

Resultset: Validation messages

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

Columns:

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

Examples

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
AS
BEGIN

	SELECT
		-- Used when updating, hidden using field info of type "hidden"
		MRT.MultiRowTableId,
		-- Columns to edit
		MRT.MultiRowExampleColumnA,
		MRT.MultiRowExampleColumnB,
		MRT.MultiRowExampleColumnC
	FROM
		Example.MultiRowTable MRT
	WHERE
		MRT.OwnerObjectId = @Id
	ORDER BY
		MRT.MultiRowExampleColumnA

END

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
AS
BEGIN

	-- We operate on a CTE to avoid doing anything to rows belonging to other OwnerObjectIds
	;WITH
		-- T as in Target, the table into which we want to MERGE data
		T AS (
			SELECT
				*
			FROM
				Example.MultiRowTable MRT
			WHERE
				MRT.OwnerObjectId = @Id
		)
	MERGE
		T
	USING
		-- S as in Source, the source data for our MERGE
		(
			SELECT
				*
			FROM
				#ExampleMultiRow
		) 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
	WHEN NOT MATCHED BY TARGET THEN
		INSERT
		(
			OwnerObjectId,
			MultiRowExampleColumnA,
			MultiRowExampleColumnB,
			MultiRowExampleColumnC
		)
		VALUES
		(
			@Id,
			S.MultiRowExampleColumnA,
			S.MultiRowExampleColumnB,
			S.MultiRowExampleColumnC
		)
	-- If a match was found between source and target 
	-- we want to update the target row with new data
	WHEN MATCHED THEN
		UPDATE
		SET
			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
	WHEN NOT MATCHED BY SOURCE THEN
		DELETE;

END

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