- name
- field-service-data-capture-reference-configure
- description
- Build, edit, and deploy Salesforce Data Capture Flows (processType DataCaptureFlow) — Field Service mobile / offline forms. Use when authoring flow-meta.xml with runtime_service_fieldservice:dc* components, Repeater loops (.AllItems), master-detail child record persistence, visual polish (gradient banners, progress bars, callouts), supporting objects with FLS/permsets, debugging DataCaptureFlow deploy errors, or troubleshooting why a deployed form doesn't appear on the FSL Mobile Forms tab (DDC/WorkPlan OWD + AssignedResource sharing prerequisites).
- user-invocable
- false
- metadata
- {"version":"1.0","domains":["Field Service"],"cliTools":[{"tool":"[Truncated]","semver":">=3.9.0"},{"tool":"[Truncated]","semver":">=2.0.0"}]}
# Querying Fs Data Capture Reference
## When to Use This Skill
Build, edit, and deploy Salesforce Data Capture Flows (processType DataCaptureFlow) — Field Service mobile / offline forms. Use when authoring flow-meta.xml with runtime_service_fieldservice:dc* components, Repeater loops (.AllItems), master-detail child record persistence, visual polish (gradient banners, progress bars, callouts), supporting objects with FLS/permsets, debugging DataCaptureFlow deploy errors, or troubleshooting why a deployed form doesn't appear on the FSL Mobile Forms tab (DDC/WorkPlan OWD + AssignedResource sharing prerequisites).
## Workflow
# Salesforce Data Capture Flow Skill
Build, edit, and deploy Salesforce Flows with `processType: DataCaptureFlow` (Field Service mobile / offline forms).
---
## Required metadata (every flow)
```xml
<processType>DataCaptureFlow</processType>
<areMetricsLoggedToDataCloud>false</areMetricsLoggedToDataCloud>
<environments>Offline</environments>
<!-- NO <apiVersion> tag -->
```
Optional `IsLlmTargetable` custom property — if you include it, it must be a JSON string, not a boolean:
```xml
<customProperties>
<name>IsLlmTargetable</name>
<value><stringValue>{"value":"false"}</stringValue></value>
</customProperties>
```
The `<booleanValue>false</booleanValue>` form deploys but blocks activation — error: `The value of the IsLlmTargetable custom property's value field must be a string in JSON format`. Omitting the property entirely is also fine.
---
## XML structure rules
Salesforce's Flow schema enforces grouping — all elements of the same type must appear in a single contiguous block. Deploy fails with `Element X is duplicated at this location` when violated.
Group order doesn't matter, but within each group elements must be adjacent:
- all `<choices>` together
- all `<dynamicChoiceSets>` together
- all `<screens>` together
- all `<decisions>` together
- all `<recordLookups>` together
- all `<recordCreates>` together
- all `<recordUpdates>` together
- all `<loops>` together
- all `<assignments>` together
- all `<variables>` together
Connector references determine execution order, not XML order.
---
## Component reference
All extensions: prefix `runtime_service_fieldservice:`
| Component | Extension | fieldType |
|-----------|-----------|-----------|
| Short Text | `dcTextInput` | `ComponentInstance` |
| Long Text | `dcLongText` | `ComponentInstance` |
| Email | `dcEmail` | `ComponentInstance` |
| Phone | `dcPhone` | `ComponentInstance` |
| Name | `dcName` | `ComponentInstance` |
| Numeric | `dcNumeric` | `ComponentInstance` |
| Counter | `dcCounter` | `ComponentInstance` |
| Date | `dcDate` | `ComponentInstance` |
| Date & Time | `dcDateTime` | `ComponentInstance` |
| Checkbox | `dcCheckbox` | `ComponentInstance` |
| Toggle | `dcToggle` | `ComponentInstance` |
| Address / GPS | `dcAddress` | `ComponentInstance` |
| Lookup | `dcLookup` | `ComponentInstance` |
| Static image | `dcFileView` | `ComponentInstance` |
| Upload image (mobile) | `dcUpImage` | `ComponentInstance` |
| Upload file (mobile) | `dcUpFile` | `ComponentInstance` |
| Signature (mobile) | `dcSignature` | `ComponentInstance` |
| Picklist single | `dcPicklist` | `ComponentChoice` |
| Picklist multi | `dcPicklist` | `ComponentMultiChoice` |
| Radio buttons | `dcRbGroup` | `ComponentChoice` |
| Checkbox group | `dcCbGroup` | `ComponentMultiChoice` |
| Matrix | `dcMatrix` | `ComponentMultiChoice` |
| Display text | *(none)* | `DisplayText` |
| Section | *(none)* | `RegionContainer` + `Region` |
| Repeater | *(none)* | `Repeater` |
Note: `<fieldType>Range</fieldType>` is NOT a valid slider fieldType in DataCaptureFlow (despite "Range/Slider" appearing in Builder UI lists). Sliders aren't available as pure metadata in this process type — use `dcNumeric` or `dcCounter`. `forceContent:repeater` (Lightning generic) ≠ `<fieldType>Repeater</fieldType>` (FSL offline). They share a concept, not XML.
### Setting the label
| fieldType | How |
|-----------|-----|
| `ComponentInstance` | `<inputParameters><name>label</name><value><stringValue>…</stringValue></value></inputParameters>` |
| `ComponentChoice` / `ComponentMultiChoice` | `<fieldText>Label</fieldText>` |
| `DisplayText` | `<fieldText>HTML</fieldText>` |
All ComponentInstance extensions (including `dcAddress` and `dcToggle`) accept the `label` inputParameter — no wrapping DisplayText needed.
### Required flag
Every input field needs `<isRequired>true/false</isRequired>` at field level. That single flag is sufficient for every `dc*` component — no extra `required` / `isRequired` inputParameter is needed.
`dcLookup` additionally accepts an `isRequired` inputParameter (boolean), but the field-level `<isRequired>` drives enforcement.
`dcCheckbox` and `dcToggle` accept `<isRequired>true</isRequired>` syntactically but don't enforce it at runtime.
### Every input field must also have
```xml
<inputsOnNextNavToAssocScrn>UseStoredValues</inputsOnNextNavToAssocScrn>
<storeOutputAutomatically>true</storeOutputAutomatically>
<styleProperties>
<verticalAlignment><stringValue>top</stringValue></verticalAlignment>
<width><stringValue>12</stringValue></width>
</styleProperties>
```
**Exception:** `<fieldType>Repeater</fieldType>` explicitly rejects `storeOutputAutomatically` (`"the storeOutputAutomatically field isn't supported"`). Repeater output is always available as `.AllItems` — no opt-in needed.
---
## Screen rules
Every screen needs ALL THREE of these or the Next/Finish button won't render:
- `<allowFinish>true</allowFinish>` (even on non-final screens)
- `<showFooter>true</showFooter>`
- `<nextOrFinishButtonLabel>Next</nextOrFinishButtonLabel>`
Plus:
- First element after `<start>` must always be a `<screens>` element
- All `<screens>` elements must be grouped together in the XML
---
## Repeater — iterating rows and creating child records
The Repeater's output collection is exposed as `.AllItems`. Confirmed working on API v66.
```xml
<!-- On the screen: -->
<fields>
<name>MyRepeater</name>
<fieldType>Repeater</fieldType>
<!-- NO storeOutputAutomatically on the Repeater itself -->
<fields>
<name>Row_PartName</name>
<extensionName>runtime_service_fieldservice:dcTextInput</extensionName>
<fieldType>ComponentInstance</fieldType>
<storeOutputAutomatically>true</storeOutputAutomatically>
<!-- … -->
</fields>
<fields>
<name>Row_PartQty</name>
<extensionName>runtime_service_fieldservice:dcCounter</extensionName>
<fieldType>ComponentInstance</fieldType>
<storeOutputAutomatically>true</storeOutputAutomatically>
<!-- … -->
</fields>
<isRequired>false</isRequired>
</fields>
<!-- At end of flow: -->
<loops>
<name>Loop_Parts</name>
<collectionReference>MyRepeater.AllItems</collectionReference> <!-- ← THE KEY -->
<iterationOrder>Asc</iterationOrder>
<nextValueConnector>
<targetReference>Create_Part</targetReference>
</nextValueConnector>
</loops>
<recordCreates>
<name>Create_Part</name>
<object>CustomFormPart__c</object>
<connector>
<targetReference>Loop_Parts</targetReference> <!-- loops back -->
</connector>
<inputAssignments>
<field>PartName__c</field>
<value>
<elementReference>Loop_Parts.Row_PartName.value</elementReference>
<!-- ↑ LOOP name + nested field name + .value -->
</value>
</inputAssignments>
<inputAssignments>
<field>Quantity__c</field>
<value>
<elementReference>Loop_Parts.Row_PartQty.value</elementReference>
</value>
</inputAssignments>
<storeOutputAutomatically>true</storeOutputAutomatically>
</recordCreates>
```
**Don'ts:**
- `<collectionReference>MyRepeater</collectionReference>` → `Element "MyRepeater" doesn't exist`
- `<collectionReference>MyRepeater.items</collectionReference>` → generic server error
- `<collectionReference>MyRepeater.data</collectionReference>` → generic server error
- Inside the loop body, `MyRepeater.Row_PartName.value` won't work — must use the **loop's name**, not the repeater's name.
**Cross-row validation does NOT compile.** Formula refs like `r_GR4.AllItems[$Items].field.value` and `r_GR4.AllItems[$Items - 1].field.value` fail with *Syntax error*. Per-row validation works via plain `fieldName.value` inside the nested field's own `validationRule`. For cross-row rules, use a post-screen `loops + decisions`.
**Other Repeater accessors don't resolve today.** Only `.AllItems` works. `AddedItems`, `PrepopulatedItems`, `RemovedItems` all fail deploy with `doesn't exist`.
### Prepopulating a Repeater from an existing collection
Bind an existing SObject collection to the Repeater so it renders one pre-filled row per source record. The user can then edit, add, or remove rows before submit.
Pattern: `recordLookups` (get source collection, `getFirstRecordOnly=false`, `storeOutputAutomatically=true`) → screen with `Repeater` bound via the `collection` inputParameter → nested fields use `SourceCollection[$EachItem].FieldApiName` as their `value` default.
```xml
<recordLookups>
<name>Get_Source</name>
<object>ServiceResource</object>
<getFirstRecordOnly>false</getFirstRecordOnly>
<storeOutputAutomatically>true</storeOutputAutomatically>
<connector><targetReference>Screen_Repeater</targetReference></connector>
<!-- optional <limit>, <filters> … -->
</recordLookups>
<!-- On the screen: -->
<fields>
<name>accountRepeater</name>
<fieldType>Repeater</fieldType>
<inputParameters>
<name>collection</name> <!-- ← binds source rows -->
<value><elementReference>Get_Source</elementReference></value>
</inputParameters>
<fields>
<name>account_info</name>
<fieldType>DisplayText</fieldType>
<fieldText><p>Id: {!Get_Source[$EachItem].Id}</p></fieldText>
<!-- DisplayText inside the Repeater merges via SourceCollection[$EachItem].Field -->
</fields>
<fields>
<name>name</name>
<extensionName>runtime_service_fieldservice:dcTextInput</extensionName>
<fieldType>ComponentInstance</fieldType>
<inputParameters>
<name>label</name>
<value><stringValue>Name</stringValue></value>
</inputParameters>
<inputParameters>
<name>value</name>
<value><elementReference>Get_Source[$EachItem].Name</elementReference></value>
<!-- ↑ prepopulates the editable field with the source record's value -->
</inputParameters>
<isRequired>true</isRequired>
<storeOutputAutomatically>true</storeOutputAutomatically>
<inputsOnNextNavToAssocScrn>UseStoredValues</inputsOnNextNavToAssocScrn>
<styleProperties>…</styleProperties>
</fields>
<isRequired>false</isRequired>
<styleProperties>…</styleProperties>
</fields>
```
Key points:
- The binding inputParameter is named `collection`, not `value` or `source`.
- Inside the Repeater, reference a source row via `SourceCollectionName[$EachItem].FieldApiName` — use the **record-lookup's name**, not the Repeater's name. Works in both `DisplayText.fieldText` (as `{!Get_Source[$EachItem].Id}`) and in component `value` defaults (as `<elementReference>Get_Source[$EachItem].Name</elementReference>`).
- `$EachItem` is the per-row iterator Salesforce injects while rendering the Repeater. It only resolves inside Repeater-nested fields.
- Downstream loops still iterate `Repeater_Name.AllItems` as normal — prepopulation changes the input, not the output accessor.
- Prepopulated rows appear as regular `.AllItems` entries after submit; there is no `PrepopulatedItems` / `AddedItems` split (those accessors fail deploy).
### Displaying Repeater entries to the user (post-Repeater Loop screen)
To show the user what they captured (e.g. review / confirmation / per-row detail), put a Loop **after** the Repeater screen whose body connects to a display screen; the display screen then connects back to the Loop. The end connector of the Loop moves on to the next step.
```xml
<loops>
<name>Loop_Through_Repeater</name>
<collectionReference>accountRepeater.AllItems</collectionReference>
<iterationOrder>Asc</iterationOrder>
<nextValueConnector>
<targetReference>Repeater_Output_Screen</targetReference> <!-- body = display screen -->
</nextValueConnector>
<!-- <noMoreValuesConnector> → next step after the review is done -->
</loops>
<screens>
<name>Repeater_Output_Screen</name>
<connector><targetReference>Loop_Through_Repeater</targetReference></connector> <!-- back to loop -->
<fields>
<name>display_info</name>
<fieldType>DisplayText</fieldType>
<fieldText><p>Source Id: {!Loop_Through_Repeater.UniqueField__Id}</p>
<p>Name: {!Loop_Through_Repeater.name.value}</p>
Voir sur GitHub