Portal Community

The Entity Binding Pattern

An "entity detail" page in App Studio follows this pattern:

  1. User navigates to /leads/lead-123 — route param id = "lead-123"
  2. A widget (typically a Form or custom container) has a data source bound to the entity lookup method
  3. The widget fetches GetLeadById(id: "lead-123") on mount
  4. The entity fields are available as {{ entityData.fieldName }} in nested widgets
  5. If the route changes (different id), the widget re-fetches automatically

Form Widget Entity Binding

The Form Widget (Atlas Form embed) supports entity pre-fill through its prefillData config:

// Form Widget on a Lead Detail page (/leads/:id)
{
  "widgetId": "lead-detail-form",
  "type": "Form",
  "config": {
    "formId": "lead-detail-atlas-form",
    "mode": "view",   // read-only
    "prefillData": {
      "leadId": "{{ route.id }}"
      // Atlas Form calls its own data source to load the full record
    }
  }
}

DataGrid Entity Binding

For loading a list related to an entity (e.g., all activities for a lead), the DataGrid's data source and params are bound to route params:

// DataGrid — activities for the current lead
{
  "widgetId": "lead-activities",
  "type": "DataGrid",
  "config": {
    "dataSource": "GetLeadActivities",
    "params": {
      "leadId": "{{ route.id }}",
      "tenantId": "{{ context.tenantId }}"
    },
    "columns": [
      { "field": "activityType", "header": "Type" },
      { "field": "createdAt", "header": "Date" },
      { "field": "createdBy", "header": "By" },
      { "field": "notes", "header": "Notes" }
    ]
  }
}
// When route.id changes (navigating to a different lead), grid re-fetches automatically

Metric Widget Entity Binding

// Metric — count of open tasks for this lead
{
  "widgetId": "open-tasks-count",
  "type": "Metric",
  "config": {
    "value": "{{ service.GetOpenTaskCount(route.id) }}",
    "label": "Open Tasks",
    "icon": "tasks",
    "colorThreshold": { "warn": 5, "danger": 10 }
  }
}
Reactive on Route Change

All entity-bound widgets automatically re-fetch their data when the route parameters change. This means you can build a "master-detail" experience where clicking different rows in a sidebar list updates all the detail widgets in a single navigation action — no manual refresh logic needed.