# UI Control Dependencies and Structural Patterns

**Last Updated:** 2026-07-01

## Overview

Many UI controls in CG Mobile have **mandatory parent-child relationships** and **required sibling elements**. Understanding these structural dependencies prevents build errors and saves significant debugging time.

This document captures patterns discovered through production analysis and build system validation.

---

## Control Dependency Patterns

### Pattern 1: FastDataEntryGrid (Complex Composite Control)

**Key Insight:** DataGrid is NOT a standalone control. It MUST be wrapped in FastDataEntryGrid with a complete mandatory structure.

**Status:** ✅ Production Pattern (Order_FastOrder)

**Context:**
DataGrid provides tabular data display with responsive layouts. However, the XML schema requires it to be part of a larger data entry pattern that includes search and input capabilities.

#### Required Structure

```xml
<FastDataEntryGrid name="[Name]">
  
  <!-- MANDATORY: DataInputArea with search and input fields -->
  <DataInputArea name="[Name]DataInputArea">
    
    <!-- MANDATORY: DataSearchField for item lookup -->
    <DataSearchField name="[Name]DataSearchField" dataSource="ProcessContext::loItems.Items[]">
      <Items>
        <Bindings>
          <Binding target="PKey" type="Text" binding=".pKey" bindingMode="ONE_WAY" />
          <Binding target="Searchable1" type="Text" binding=".[field1]" bindingMode="ONE_WAY" />
          <Binding target="Searchable2" type="Text" binding=".[field2]" bindingMode="ONE_WAY" />
          <Binding target="SearchResultDisplay1" type="Text" binding=".[field1]" bindingMode="ONE_WAY" />
          <Binding target="SearchResultDisplay2" type="Text" binding=".[field2]" bindingMode="ONE_WAY" />
        </Bindings>
      </Items>
      <Bindings>
        <Resource target="Label" type="Label" id="SearchLabelId" defaultLabel="Search for items" />
      </Bindings>
    </DataSearchField>
    
    <!-- MANDATORY: NumberInputField for quantity/amount -->
    <NumberInputField name="quantityInputField" formatV2="4.0">
      <Bindings>
        <Resource target="Label" type="Label" id="QuantityLabelId" defaultLabel="Quantity" />
      </Bindings>
    </NumberInputField>
    
    <!-- MANDATORY: Events for add/delete operations -->
    <Events>
      <CreateNewRecordEvent event="AddItemToGrid">
        <Params>
          <Param name="field1" value=".field1" />
          <Param name="field2" value=".field2" />
        </Params>
      </CreateNewRecordEvent>
    </Events>
    
  </DataInputArea>
  
  <!-- MANDATORY: DataGrid for tabular display -->
  <DataGrid name="[Name]DataGrid" dataSource="ProcessContext::loItems" paging="false">
    <Bindings>
      <Resource target="EmptyImage" type="Image" id="EmptyCart_ES" />
      <Resource target="EmptyMessage" type="Label" id="EmptyMessageId" defaultLabel="No items available." />
    </Bindings>
    <Items>
      <Bindings>
        <!-- Column bindings -->
        <Binding target="PKey" type="Text" binding=".pKey" bindingMode="ONE_WAY" />
        <Binding target="Field1" type="Text" binding=".field1" bindingMode="ONE_WAY" />
        <Binding target="Field2" type="Text" binding=".field2" bindingMode="ONE_WAY" />
        
        <!-- Header resource bindings -->
        <Resource target="field1Header" type="Label" id="Field1HeaderId" defaultLabel="Field 1" />
        <Resource target="field2Header" type="Label" id="Field2HeaderId" defaultLabel="Field 2" />
      </Bindings>
      
      <!-- MANDATORY: GridLayout defines table structure -->
      <GridLayout>
        <Default>
          <Header>
            <Col bindingId="field1Header" align="left" />
            <Col bindingId="field2Header" align="left" />
          </Header>
          <Col width="50%" layoutType="Text" bindingId="Field1" />
          <Col width="50%" layoutType="Text" bindingId="Field2" />
        </Default>
        <Tablet>
          <Header>
            <Col bindingId="field1Header" align="left" />
            <Col bindingId="field2Header" align="left" />
          </Header>
          <Col width="60%" layoutType="Text" bindingId="Field1" />
          <Col width="40%" layoutType="Text" bindingId="Field2" />
        </Tablet>
        <Phone>
          <Header>
            <Col bindingId="field1Header" align="left" />
          </Header>
          <Col width="100%" layoutType="Text" bindingId="Field1" />
        </Phone>
      </GridLayout>
    </Items>
    <Events>
      <DeleteRecordEvent event="DeleteItemFromGrid">
        <Params>
          <Param name="field" value=".field" />
        </Params>
      </DeleteRecordEvent>
    </Events>
  </DataGrid>
  
</FastDataEntryGrid>
```

#### Backend Requirements

- ✅ ListObject with Items[] array
- ✅ ListItem with SimpleProperties matching column bindings
- ✅ DataSource (can be minimal for mock data scenarios)
- ❌ NO Table contract needed (GridLayout defines columns directly)

#### Build Errors to Watch

**Error 1: DataGrid Not Expected**
```
Element 'DataGrid': This element is not expected.
```
**Cause:** DataGrid used as standalone control  
**Solution:** Wrap in FastDataEntryGrid parent

**Error 2: Missing DataInputArea**
```
Element 'FastDataEntryGrid': Missing child element(s). Expected is ( DataInputArea ).
```
**Cause:** FastDataEntryGrid created without required DataInputArea child  
**Solution:** Add complete DataInputArea structure

**Error 3: Incomplete DataInputArea**
```
Element 'DataInputArea': Missing child element(s). Expected is one of ( NumberInputField, Events ).
```
**Cause:** DataInputArea missing required children  
**Solution:** Add DataSearchField + NumberInputField + Events

#### Production Example

**Location:** `src/Order/PR/Order_FastOrder/Order_FastOrderUI.userinterface.xml` (lines 31-116)

**Key Points:**
- FastDataEntryGrid lives in SingleElementArea
- DataSearchField binds to ProcessContext::loItems.Items[] for search
- DataGrid binds to ProcessContext::loItems for display
- GridLayout has three responsive variants (Default/Tablet/Phone)
- Column widths adjust per device type

---

### Pattern 2: Label and Image (Binding Targets Only)

**Key Insight:** Label and Image are NOT standalone UI elements. They only exist as Resource binding targets within other controls.

**Status:** ✅ Confirmed Pattern

#### The Wrong Approach

```xml
❌ WRONG - Cannot use as standalone elements:

<GroupElement name="Example">
  <Label text="Hello World" />  <!-- FAILS: Element 'Label' is not expected -->
  <Image imageId="Logo" />       <!-- FAILS: Element 'Image' is not expected -->
</GroupElement>
```

**Build Error:**
```
Element 'Label': This element is not expected. Expected is one of ( InputArea, ... ).
```

#### The Correct Approach

```xml
✅ CORRECT - Use as Resource bindings:

<InputArea name="CustomerName">
  <Bindings>
    <Resource target="Label" type="Label" id="CustomerNameLabelId" defaultLabel="Customer Name" />
    <Binding target="Value" binding="ProcessContext::customerName" bindingMode="TWO_WAY" />
  </Bindings>
</InputArea>

<ImageButton name="ActionButton">
  <Bindings>
    <Resource target="Image" type="Image" id="ActionIcon" />
    <Resource target="Text" type="Label" id="ActionLabelId" defaultLabel="Action" />
  </Bindings>
  <Events>
    <ButtonPressedEvent event="OnActionPressed" />
  </Events>
</ImageButton>
```

#### Where Labels Are Used

Labels appear as Resource binding targets in:
- **InputArea** - Field labels
- **MenuItem** - Menu item text
- **GroupElement** - Section titles
- **DataGrid** - Column headers (via Items/Bindings/Resource)
- **ImageButton** - Button text
- **PageHeader** - Page title

#### Where Images Are Used

Images appear as Resource binding targets in:
- **ImageButton** - Button icons
- **DataGrid** - Empty state image
- **MenuItem** - Menu item icons
- **PageHeader** - Logo icons

#### Common Pattern: InputArea with Label

```xml
<InputArea name="EmailAddress">
  <Bindings>
    <!-- Label binding target -->
    <Resource target="Label" type="Label" id="EmailLabelId" defaultLabel="Email Address" />
    
    <!-- Value binding -->
    <Binding target="Value" type="Text" binding="ProcessContext::email" bindingMode="TWO_WAY" />
    
    <!-- Validation binding -->
    <Binding target="Valid" type="Boolean" binding="ProcessContext::emailValid" bindingMode="ONE_WAY" />
  </Bindings>
</InputArea>
```

---

### Pattern 3: ImageButton Container Restrictions

**Key Insight:** ImageButton is commonly placed in ButtonGridArea, or inside LinkBar/ActionBar within a CardContainer. Using it in wrong containers (GroupElement, GroupedElementsArea) causes build errors.

**Status:** ✅ Confirmed Pattern

#### Valid Containers

```xml
✅ ButtonGridArea (Most common - dashboards)

<Area areaName="buttonGridArea" areaPattern="ButtonGridArea">
  <ImageButton name="Feature1Btn">
    <Bindings>
      <Resource target="Image" type="Image" id="Feature1Icon" />
      <Resource target="Text" type="Label" id="Feature1LabelId" defaultLabel="Feature 1" />
    </Bindings>
    <Events>
      <ButtonPressedEvent event="OnFeature1Pressed" />
    </Events>
  </ImageButton>
</Area>
```

```xml
✅ LinkBar inside CardContainer (Navigation links in cockpit cards)

<Area areaName="mainArea" areaPattern="Card">
  <CardContainer name="CardVisits">
    <Bindings>
      <Resource target="Title" type="Label" id="VisitsCardTitleId" defaultLabel="My Visits" />
    </Bindings>
    <LinkBar>
      <ImageButton name="CalendarLink">
        <Bindings>
          <Resource target="Image" type="Image" id="CalendarIcon" />
          <Resource target="Text" type="Label" id="CalendarLinkId" defaultLabel="Calendar" />
        </Bindings>
        <Events>
          <ButtonPressedEvent event="OpenCalendar" />
        </Events>
      </ImageButton>
    </LinkBar>
  </CardContainer>
</Area>
```

```xml
✅ ActionBar inside CardContainer (Action buttons in cockpit cards)

<Area areaName="mainArea" areaPattern="Card">
  <CardContainer name="CardOrders">
    <Bindings>
      <Resource target="Title" type="Label" id="OrdersCardTitleId" defaultLabel="Orders" />
    </Bindings>
    <ActionBar>
      <ImageButton name="AddNewOrder">
        <Bindings>
          <Resource target="Image" type="Image" id="AddIcon" />
          <Resource target="Text" type="Label" id="AddOrderId" defaultLabel="New Order" />
        </Bindings>
        <Events>
          <ButtonPressedEvent event="CreateOrder" />
        </Events>
      </ImageButton>
    </ActionBar>
  </CardContainer>
</Area>
```

**Note:** LinkBar and ActionBar are **card constructs** — they require a Card/CardContainer context. They are NOT standalone `areaPattern` values. Valid `areaPattern` values include: `SingleElementArea`, `GroupedElementsArea`, `MultiArea`, `TabElementArea`, `Card`, `FilterElementArea`, `WelcomeArea`, `ButtonGridArea`.

**Other Valid Contexts:** The XML schema also permits ImageButton in additional contexts including `Area`, `AreaHeader`, `Actions`, `ButtonGroup`, `HeaderLine`, and `CockpitSection`. Check production examples when using these less common containers.

#### Invalid Containers

```xml
❌ GroupElement

<GroupElement name="FormSection">
  <ImageButton name="ActionBtn">  <!-- FAILS -->
    ...
  </ImageButton>
</GroupElement>
```

**Build Error:**
```
Element 'ImageButton': This element is not expected.
Expected is one of ( InputArea, Merger, DatePickerField, ... ).
```

**Solution:** Use different control (e.g., InputArea with button-like styling) or move ImageButton to valid container.

```xml
❌ GroupedElementsArea (direct child)

<Area areaName="mainArea" areaPattern="GroupedElementsArea">
  <ImageButton name="ActionBtn">  <!-- FAILS -->
    ...
  </ImageButton>
</Area>
```

**Solution:** Change area pattern to ButtonGridArea, or use a CardContainer with ActionBar/LinkBar, or use allowed controls for GroupedElementsArea.

---

## Control Categories by Complexity

### Simple Controls (Standalone)

These work independently with ProcessContext bindings only:

- **InputArea** - Text/number input fields
- **MenuItem** - Menu items in PageHeader
- **Merger** - Combined input with buttons (phone + call)
- **DatePickerField** - Date selection
- **TimePickerField** - Time selection
- **Stepper** - Numeric stepper
- **CheckBox** (ToggleButton) - Boolean toggle
- **InputAreaMultiLine** - Multi-line text

**Pattern:**
```xml
<ProcessContext>
  <Declarations>
    <Declaration name="fieldName" type="DomString" />
  </Declarations>
</ProcessContext>

<!-- In UI -->
<InputArea name="Field">
  <Bindings>
    <Resource target="Label" type="Label" id="FieldLabelId" defaultLabel="Field Name" />
    <Binding target="Value" binding="ProcessContext::fieldName" bindingMode="TWO_WAY" />
  </Bindings>
</InputArea>
```

### Complex Controls (Infrastructure Required)

These need full BO/LO/DS infrastructure:

- **FastDataEntryGrid + DataGrid** - Needs LO + complete structure (this pattern)
- **GroupedList** - Needs LO + ItemListLayout
- **CardContainer** - Needs CardController BO + LoadContainerData events
- **Dropdown** - Needs LO + FilterElement type
- **ImageSelector** - Needs LO + visual tiles
- **SelectionBox** - Needs Toggle domain definition

**Pattern:**
```xml
<!-- Requires: -->
- ListObject/ListItem/DataSource definitions
- Business Logic methods
- Process EntryActions for instantiation and loading
- Event handlers in Process
```

---

## Best Practices

### 1. Always Check Production for Rare Controls

When implementing a rarely-used control (DataGrid, ImageGrid, TextBar):

1. Search production contracts:
   ```bash
   rg -l "DataGrid" src/ --type xml
   ```

2. Read the COMPLETE implementation:
   - UI structure (parent/child relationships)
   - Process integration (how it's instantiated)
   - BO/LO/DS infrastructure (what data structures exist)

3. Understand structural requirements:
   - What are the mandatory parent/child elements?
   - What siblings are required?
   - What backend infrastructure is needed?

**Never assume a control is standalone until you've verified in production code.**

### 2. Understand Control Hierarchies

Many "controls" are actually child elements of larger patterns:

- **DataGrid** → child of **FastDataEntryGrid**
- **DataSearchField** → child of **DataInputArea**
- **NumberInputField** → child of **DataInputArea**
- **TextBar** → child of **GroupedList**
- **Col** → child of **GridLayout**

**Implication:** You can't just copy one element. You need the complete parent structure.

### 3. Test with Real Build System

Schema validation errors are authoritative:

- ✅ If build succeeds → Pattern is correct
- ❌ If build fails → Read error message for expected structure

**Don't guess at structure.** Let the build system tell you what's required.

### 4. Document Structural Dependencies

When discovering a new pattern in production:

1. Note parent-child requirements
2. Note mandatory sibling elements
3. Note backend infrastructure needed
4. Reference production example path
5. List common build errors

This prevents others from repeating the discovery process.

---

## Common Build Error Patterns

### Error Type 1: Element Not Expected

**Pattern:**
```
Element '[ControlName]': This element is not expected.
Expected is one of ( [ValidControls] ).
```

**Cause:** Control used in wrong context or missing parent wrapper

**Solutions:**
1. Check if control needs parent wrapper (e.g., DataGrid → FastDataEntryGrid)
2. Verify container allows this control type (e.g., ImageButton → ButtonGridArea)
3. Check production examples for correct usage context

### Error Type 2: Missing Child Elements

**Pattern:**
```
Element '[ParentControl]': Missing child element(s).
Expected is ( [RequiredChildren] ).
```

**Cause:** Incomplete control structure - parent exists but required children missing

**Solutions:**
1. Add all mandatory child elements
2. Check production for complete structure
3. Don't assume any children are optional without verification

### Error Type 3: Wrong Attribute

**Pattern:**
```
Element '[Control]', attribute '[AttributeName]': The attribute '[AttributeName]' is not allowed.
```

**Cause:** Using attribute not supported in schema

**Solutions:**
1. Check production examples for correct attribute names
2. Verify schema version matches
3. Remove unsupported attribute

---

## Testing Strategy

### For Complex Controls (FastDataEntryGrid, GroupedList)

1. **Create complete infrastructure:**
   - ListObject/ListItem/DataSource
   - Business Logic methods
   - Process integration

2. **Test with mock data:**
   - Use createTestData pattern for UI testing
   - Verify data appears in grid/list
   - Test responsive layouts (Default/Tablet/Phone)

3. **Verify events:**
   - Test add/delete operations
   - Verify ProcessContext updates
   - Test navigation flows

### For Simple Controls (InputArea, CheckBox)

1. **Test TWO_WAY bindings:**
   - Enter data in UI
   - Verify ProcessContext variable updates
   - Update ProcessContext in code
   - Verify UI reflects change

2. **Test validation:**
   - Test valid and invalid inputs
   - Verify validation feedback displays
   - Test error messages

---

## Related Documentation

- [Create UI Page](../skills/create-ui-page/SKILL.md) - UI fundamentals
- [Create ListObject](../skills/create-list-object/SKILL.md) - LO infrastructure for complex controls
- [Create Process](../skills/create-process/SKILL.md) - Process integration patterns
- [Build Error Quick Reference](../reference/build-error-quick-reference.md) - Error lookup table

---

**Key Takeaway:** Don't assume. Always verify control structure with production code and build system. The schema is the source of truth for mandatory parent-child relationships.
