MLoadRecords Class

Overview

The MLoadRecords class handles loading form schemas and records from companion Fulcrum apps. It creates a dictionary to convert form_value keys to data_name keys for easier access to record data.

Common Use Cases

  • Load records from a linked app based on a record link field
  • Refresh a record link field when records in the linked app reference this record
  • Prevent duplicate record selection across records in this app

Quick Start

const appID = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'

function processRecordsCallback() {
  const loadedRecords = loader.appRecords
  const titleList = loadedRecords.map(x => x.scientific_name + ' - ' + x.common_name)
  SETVALUE('result', titleList.join('\n'))
}

const loader = M.mkMLoadRecords(appID, processRecordsCallback)
loader.dnRecLink = 'species_link'

ON('load-record', loader.buildAppFvDict)
ON('change', 'species_link', loader.updateLoadedRecords)

Method Flow Diagrams

The following diagrams show how methods chain together in the MLoadRecords class.

Diagram 1: buildAppFvDict / getAppFvs Flow

Used in ON('load-record') to initialize the loader.

buildAppFvDict(event)                    getAppFvs(event)
       │                                        │
       │                                        ├── recordsOnLoad = true
       │                                        │
       └────────────────┬───────────────────────┘
                        │
                        ▼
               loadForm(formID, processForm)
                        │
                        ▼
                 processForm(form)
                        │
                        ├── appFvs = {form_value_key: data_name, ...}
                        │
                        ▼
                ┌───────────────────┐
                │  recordsOnLoad?   │
                └───────────────────┘
                        │
           ┌────────────┴────────────┐
           │                         │
       FALSE                       TRUE
           │                         │
           ▼                         ▼
        (STOP)              ┌────────────────┐
                            │  dnRefreshRL?  │
      Records loaded        └────────────────┘
      later via                     │
      ON('change')         ┌────────┴────────┐
                           │                 │
                       NOT SET             SET
                           │                 │
                           ▼                 ▼
               updateLoadedRecords()   refreshRecordLink()
                           │                 │
                           │                 │
                     (see Diagram 2)    (see Diagram 3)

Key Points:

  • buildAppFvDict does NOT set recordsOnLoad, so it stops after building the dictionary
  • getAppFvs sets recordsOnLoad = true, so it continues to load records
  • Use buildAppFvDict when you want to load records later via ON('change')
  • Use getAppFvs when you want to load all records immediately on form load

Diagram 2: updateLoadedRecords Flow

Used in ON('change') for record link field, or called automatically from processForm when recordsOnLoad is true.

updateLoadedRecords(event)
           │
           ├── ids = VALUE(dnRecLink).map(x => x.record_id)
           │
           ▼
   ┌───────────────┐
   │  ids exist?   │
   └───────────────┘
           │
     ┌─────┴─────┐
     │           │
    NO          YES
     │           │
     ▼           ▼
clearAutoFields()   loadRecords(ids, processRecords)
     │                          │
     ▼                          ▼
  (STOP)              processRecords(records)
                                │
                                ▼
                    _processRecordResults(records)
                                │
                                ├── appRecords = converted records
                                │
                                ▼
                       ┌─────────────────────┐
                       │ recordsOnLoad AND   │
                       │ enterLoadedData?    │
                       └─────────────────────┘
                                │
                          ┌─────┴─────┐
                          │           │
                        FALSE       TRUE
                          │           │
                          ▼           ▼
                       (STOP)   enterLoadedData(records)
                                      │
                                      ▼
                                   (STOP)

                          User callback processes
                          records (e.g., populate
                          fields, build lists)

Key Points:

  • Extracts record IDs from the configured dnRecLink field
  • If no IDs found, clears auto-populated fields and stops
  • enterLoadedData callback only runs if recordsOnLoad is true

Diagram 3: refreshRecordLink Flow

Finds records in linked app that reference THIS record (reverse lookup).

refreshRecordLink()
         │
         ├── opts = filterTemplate(dnRefreshRL, "contains", RECORDID())
         │
         ▼
loadRecords(opts, processRefreshRL)
         │
         ▼
processRefreshRL(records)
         │
         ▼
_processRecordResults(records)
         │
         ├── appRecords = converted records
         │
         ▼
  ┌──────────────┐
  │ has records? │
  └──────────────┘
         │
   ┌─────┴─────┐
   │           │
  NO          YES
   │           │
   ▼           ▼
(STOP)   ids = appRecords.map(x => x.id)
               │
               ▼
         SETVALUE(dnRecLink, ids)
               │
               ▼
         addOnRefreshRL()
               │
               ▼
            (STOP)

         User callback for
         additional processing

Key Points:

  • Queries for records where dnRefreshRL field contains current RECORDID()
  • Updates dnRecLink with the IDs of matching records
  • Useful for parent-child relationships where child records link to parent

Diagram 4: selfDupCheck Flow

Prevents duplicate record selection across records in this app.

selfDupCheck(event)
         │
         ├── id = event.value[0].record_id
         │
         ▼
   ┌────────────┐
   │  id exist? │
   └────────────┘
         │
   ┌─────┴─────┐
   │           │
  NO          YES
   │           │
   ▼           ▼
clearAutoFields()   SETVALUE(dnRecLinkIds, id)
   │                          │
   ▼                          ▼
(STOP)        loadRecords(filterTemplate(...), processSelfDupCheck)
                              │
                              ▼
                   processSelfDupCheck(records)
                              │
                              ▼
                  _processRecordResults(records)
                              │
                              ▼
                    ┌───────────────────────┐
                    │ Is current record in  │
                    │ results? (not a dup)  │
                    └───────────────────────┘
                              │
                        ┌─────┴─────┐
                        │           │
                       YES         NO (duplicate!)
                        │           │
                        ▼           ▼
                     (STOP)   clearAutoFields()
                                    │
                                    ▼
                            SETVALUE(dnRecLink, null)
                                    │
                                    ▼
                              duplicateAlert()
                                    │
                                    ▼
                                 (STOP)

Key Points:

  • Requires dnRecLink, dnRecLinkIds, and optionally dnsRecLinkAuto to be configured
  • Stores the selected record ID in a text field (dnRecLinkIds) for querying
  • If another record already links to the same target, clears selection and shows alert

Configuration Properties

Property Type Description
formID string Fulcrum form ID of the linked app
enterLoadedData Function|null Callback to process records after loading
recIDs Array<string>|null Array of record IDs to load
appFvs Object Dictionary mapping form_value keys to data_names
appRecords Array<Object>|null Loaded records with data_name keys
recordsOnLoad boolean If true, loads records immediately after form schema
sortOrder Array<Array>|null Sort order for queries, e.g., [['report_id', 'dsc']]
dnRecLink string THIS app data name of record link field
dnRecLinkIds string CHILD app data name of text field storing record IDs
dnsRecLinkAuto Array<string> Data names to clear if duplicate found
dnRefreshRL string CHILD app data name that links back to this record (this.dnRecLink)
addOnRefreshRL Function Additional callback after refreshing record link
duplicateAlert Function Function to call when duplicate detected
helpers FulcrumHelpers FulcrumHelpers instance for utility methods

Examples

Example 1: Load Records on Change

Load species data when a record link field changes.

const speciesAppID = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'

function displaySpeciesInfo() {
  const records = loader.appRecords
  if (!records) return

  const info = records.map(r => `${r.scientific_name} (${r.common_name})`).join('\n')
  SETVALUE('species_summary', info)
}

const loader = M.mkMLoadRecords(speciesAppID, displaySpeciesInfo)
loader.dnRecLink = 'species_link'

ON('load-record', loader.buildAppFvDict)
ON('change', 'species_link', loader.updateLoadedRecords)

Example 2: Prevent Duplicate Selection

Ensure each project can only be linked once across all records.

const projectAppID = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'

const loader = M.mkMLoadRecords(projectAppID, null)
loader.dnRecLink = 'project_link'
loader.dnRecLinkIds = 'project_id_text'  // Hidden text field to store ID for querying
loader.dnsRecLinkAuto = ['project_name', 'project_manager', 'project_date']

// Custom duplicate alert
loader.duplicateAlert = () => {
  ALERT('This project is already assigned to another record. Please choose a different project.')
}

ON('load-record', loader.buildAppFvDict)
ON('change', 'project_link', loader.selfDupCheck)

Example 3: Refresh Child Records

Automatically populate a record link with all child records that reference this parent.

const childAppID = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'

function afterRefresh() {
  const count = loader.appRecords ? loader.appRecords.length : 0
  SETVALUE('child_count', count)
}

const loader = M.mkMLoadRecords(childAppID, null)
loader.dnRecLink = 'child_records'        // Record link field in THIS app
loader.dnRefreshRL = 'parent_record_link' // Field in CHILD app that links to this record
loader.sortOrder = [['created_at', 'dsc']]
loader.addOnRefreshRL = afterRefresh

ON('load-record', loader.getAppFvs)  // Use getAppFvs to load immediately

See Also