Data Source Field
Data Source Field
The Data Source field is a non-visual field that gathers a set of data one time and shares it with one or more visual fields on the form — charts, calendars and other "consumer" fields. It separates the job of getting the data from the job of displaying it. Instead of every chart or calendar carrying its own data expression, you create a single Data Source, point it at your data, and then bind as many display fields to it as you like. Another benefit to the Data Source field is that it loads the data client side so the initial loading of the form does not wait for its data call.
Because the Data Source itself draws nothing on the screen, it appears in the designer as a labeled placeholder and is invisible to the end user when the form is run. Its only purpose is to fetch data and hand it to the fields that are bound to it.
Tip: One Data Source can feed many fields at once. For example, a single Data Source that returns a list of invoices can drive a bar chart, a calendar and a table on the same dashboard — all showing the same rows, gathered only once.
How It Works
A Data Source has a single, central setting — the Data Expression. This is the recipe that tells the server how to gather the data. Once the form is open, the Data Source sends the expression to the server, which gathers the data and returns it to the Data Source field. Any consumer fields that are bound to the Data Source then read that result and display it.
The data is gathered in these situations:
- On form load — as soon as the form opens, the Data Source asks the server for its data. The form does not wait for it: the form appears first, and the bound fields fill in when the data arrives, with the Please Wait Message showing in the meantime. To skip this first load, turn off Load Data When E-form Loads (see Settings below).
- When a referenced field changes — if your expression refers to other fields on the form using {FieldName} syntax, the Data Source automatically re-gathers the data whenever one of those fields changes. This lets a chart or calendar react live to a date range, a selected vendor, and so on.
- On demand — you can force a refresh at any time from a button or Multi-Action (see Commands below).
The Data Expression
The Data Expression supports the same server variables used elsewhere in DocMgt — the "DMGET" family of variables, SQL and REST lookups, and so on. Some common choices:
[DMGET2(...)] — searches your records and returns them as JSON rows. This is the most flexible choice and is recommended for charts. It returns an array of objects with named columns.
[DMGETEVENTS(...)] — searches your records and returns them formatted for calendars (date, description and id for each event).
[SQLGET(...)] / [RESTGET(...)] — pull data from a SQL query or a REST/internet call.
You can mix in field references with {FieldName} so the data responds to what the user enters. For example, the following gathers invoices for the vendor the user has selected and re-runs whenever that selection changes:
[DMGET2(12|0|Vendor={VendorName}|InvoiceDate^Vendor^Amount)]
Note: Server variables in square brackets — such as [DMGET2] — are always resolved on the server. The {FieldName} references are filled in first, then the completed expression is sent to the server to gather the data.
Data Format
The Data Source does not care what the data looks like — it simply holds whatever the expression produced and hands it to the consumers. The consumer fields are responsible for interpreting it. There are two common shapes:
JSON rows (recommended) — an array of objects with named columns. This is what [DMGET2] returns and is the easiest to work with, because consumers can map columns to roles by name. Example:
[{"InvoiceDate":"6/1/2025","Vendor":"ACME","Amount":"$1,200.00"}, ... ]
Delimited text — a pre-shaped string that a particular consumer understands. For example, [DMGETEVENTS] returns a calendar-shaped string of date^description^^id separated by semicolons, and a chart can accept a label^value^grouping string. These are positional — no column mapping is needed.
Connecting Consumer Fields
Consumer fields are the visual fields that display Data Source data. To connect one, edit the consumer field and choose the Data Source from its Data Source setting, then (for JSON data) map the columns to the field's roles. Fields that can consume a Data Source include:
- Data Source Chart — a bar, line, pie, doughnut or stacked chart. Map columns to Label, Value and (optionally) Grouping, and choose how to aggregate and bucket the data.
- Calendars (Month, Week, Day, Agenda) — bind a Data Source to populate calendar events instead of (or in addition to) the manual Events list. Map columns to Date, Description and ID, or feed it a [DMGETEVENTS] expression directly.
Tip: A consumer keeps its own original data option for backward compatibility. Binding a Data Source is an added option — leave it unset to keep using the field's built-in expression.
Using the Data Elsewhere
You can also read a Data Source's data from other fields and actions using the field's name:
{SourceName} — returns the whole data set (as JSON text when the data is structured).
{PROP(SourceName,Column)} — extracts a single property/column value from the data.
When you send a Data Source into an Action Set, the gathered data travels with it — useful for processing the same rows on the server.
Calculating a statistic with DSCALC
Any place on the form that accepts {field} references can compute one number over a Data Source with {DSCALC(Source,Function,Column,Filters)}: a Text Label, a Math Label term, a Stat Tile's Value, or a condition's computed value.
- Source is the Field Name of the Data Source.
- Function is sum, count, avg, min or max. Leave it blank for sum.
- Column is the column to total. Leave it blank for the first column. Count ignores it. When the Data Source holds chart data, the label and value pairs the chart variables produce, use a position such as 2 or the words label, value or grouping, and use the same in the filters, for example label=ACME.
- Decimals is optional and comes last: the number of decimal places to show, such as 2 for money. {DSCALC(AP30,sum,Amount,,2)} shows 1500.80. Leave the filters empty, as in that example, when you only want the decimals.
- Filters are optional. A filter keeps only the rows that match, and the calculation then runs on those rows. Write each condition as a column name, an operator and a value, such as Paid=YES, and join conditions with the ^ character. When there is more than one condition, a row has to match all of them: Vendor=ACME^Paid=YES keeps the paid ACME rows.
The operators:
- = — the column equals the value. Paid=YES
- <> — the column does not equal the value. != works too. Status<>Closed
- > and >= — the column is greater than the value, or at least the value. Amount>1000, InvoiceDate>=1/1/2026
- < and <= — the column is less than the value, or at most the value. Amount<0, DueDate<=12/31/2026
- Contains — the column includes the value anywhere in it. Vendor Contains ACME matches both ACME and ACME Supply.
- Not Contains — the column does not include the value anywhere in it. Notes Not Contains void
- Contained — the column equals one of several values, separated by the | character. This is the way to say "this or that" on one column. Status Contained Open|On Hold
- Not Contained — the column equals none of the listed values. Status Not Contained Closed|Void
- Empty — the column is blank. It takes no value. Paid Empty
- Not Empty — the column has any value at all. Paid Not Empty
As in a DocMgt search, Paid=# is a shorter way to write Paid Empty, and Paid=!# a shorter way to write Paid Not Empty.
How the values are compared:
- Capital letters never matter, so Paid=yes matches YES.
- When the column and the value are both numbers, they are compared as numbers, so Amount>1000 works on $1,250.00. Currency symbols and thousands separators are ignored, and an amount in parentheses, such as (50.00), counts as negative.
- When the column and the value are both dates, they are compared as dates.
- Anything else is compared as text, in alphabetical order for > and <.
- When the value is a number or a date, >, >=, < and <= skip rows whose column is blank or holds text, so Amount<0 does not pick up rows that have no amount.
Two things to check when a result looks wrong:
- The column has to be in the data. A filter can only test the columns the Data Expression returns, and [DMGET2] returns only the fields in its return list. To filter on Paid, include it there: [DMGET2(12|0||Vendor^Amount^Paid)]. A column that is missing reads as blank in every row, so Paid=YES gives 0.
- A field that holds more than one value is compared as a whole. Region=North does not match a row that holds both North and West; use Region Contains North for a field like that.
Leave the filters off to work on the whole Data Source: {DSCALC(AP30,sum,Amount)} is the total of every row and {DSCALC(AP30,count)} is the number of rows. With filters: {DSCALC(AP30,count,,Paid=YES)} counts the paid rows, {DSCALC(AP30,sum,Amount,Vendor=ACME^Paid=YES)} totals the paid ACME rows, and {DSCALC(AP30,sum,Amount,Vendor={Vendor Pick})} follows a dropdown, because a {field} inside the filter is replaced first. The result is a plain number, so a percentage is an expression around two calculations: {{DSCALC(AP30,count,,Paid=YES)}/{DSCALC(AP30,count)}*100}. The number updates whenever the Data Source loads or refreshes.
Because every condition in a filter has to match, one calculation cannot say "or" between two different columns. For "or" on a single column, use Contained. For "or" across two columns, add two calculations together and subtract the rows they have in common, so that no row is counted twice. This counts the rows that are paid or are from ACME:
{{DSCALC(AP30,count,,Paid=YES)} + {DSCALC(AP30,count,,Vendor=ACME)} - {DSCALC(AP30,count,,Paid=YES^Vendor=ACME)}}
Tip: One Data Source can drive any number of counts. Have the Data Expression return every column you will count on, then give each Text Label its own calculation, such as {DSCALC(AP30,count,,Status Contained Open|On Hold)} in one and {DSCALC(AP30,count,,Status Contained Open|On Hold^Paid=NO)} in the next. The server is asked for the data once, and every count after that is worked out on the form.
Commands
You can control a Data Source by setting its value — typically from a button or Multi-Action using a Set Field Value action. The Data Source watches its value for these special commands:
REFRESH — re-runs the Data Expression and re-gathers the data. All bound consumers update.
CLEAR — empties the data.
Any other value set on the field is treated as data being pushed directly into the Data Source — for example, an Action Set can return rows and place them into the Data Source by name, bypassing the Data Expression entirely.
Reacting When the Data Refreshes
A Data Source counts as a changed field each time it finishes loading its data, so a Multi-Action can watch it the same way it watches any other field and run its actions after every refresh. Turn on Watch for Changes on the Multi-Action, enter the Data Source's field name in E-form Fields to Watch using {FieldName} notation, and choose what counts as a refresh with Run When Equals:
- !# runs the actions after every load and refresh, whether or not the data changed. This is the usual choice.
- Blank runs them only when the data that came back differs from the previous load.
- # runs them when the Data Source has been cleared.
To react to the number of rows instead, watch {DSCALC(FieldName,count)}. Left blank, Run When Equals then means "the row count changed"; a number means "the row count is now that number".
The actions run once the data has arrived, not when the refresh starts, so anything in the actions that reads the Data Source sees the new rows. The first load when the form opens counts as a refresh too, so the actions run once at that point; use Fields to Match on the Multi-Action if they should wait for a later refresh.
Example: a dashboard refreshed by a Timer shows when it was last updated. Add a Text Label named Last Refreshed, then a Multi-Action watching {Invoices} with !# in Run When Equals and one Set Field Value action that puts [DATETIME] into Last Refreshed. Each time the Timer refreshes the Data Source, the label updates a moment later.
A Multi-Action that watches a Data Source must not send REFRESH to that same Data Source in its own actions, or each refresh triggers the next one without end.
Settings
Field Name — the name used to refer to this Data Source, both when binding consumers and when reading its data with {Name} / {PROP(Name,Column)}.
Data Expression — the expression used to gather the data (for example a [DMGET2] or [DMGETEVENTS] call). May include {FieldName} references that make the data react to other fields.
Please Wait Message — the message shown in the global Please Wait dialog while the Data Source is gathering data from the server. Supports variables. Defaults to "Loading data..."; leave it blank to show no message. When several Data Sources load at once, the dialog stays open until the last one finishes.
Load Data When E-form Loads (in the Advanced Settings) — on by default, so the Data Source gathers its data as soon as the form opens. Turn it off when the Data Expression refers to a field that starts out empty, such as a date range the user picks. The Data Source then waits until a referenced field changes or an Action sends REFRESH, instead of searching with blank values when the form opens.
Example: A Spend-by-Vendor Dashboard
1. Add a Data Source field named "Invoices" and set its Data Expression to return your invoice rows as JSON:
[DMGET2(12|0||InvoiceDate^Vendor^Amount)]
2. Add a Bar Chart, bind it to "Invoices", set the Label column to Vendor, the Value column to Amount, and aggregation to Sum. You now have spend-by-vendor.
3. Add a Calendar, bind it to the same "Invoices" Data Source, and map the Date column to InvoiceDate and the Description column to Vendor. The same rows now also appear as calendar events.
4. (Optional) Add a button with a Set Field Value action that sets "Invoices" to REFRESH so users can re-pull the data on demand.
The data is gathered once by the Data Source and shared by both the chart and the calendar — and a single REFRESH updates them together.