> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stac.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Dynamic View

> Documentation for Dynamic View

export const PLAYGROUND_BASE_URL = "https://playground.stac.dev/";

export const dynamicViewPreviewJson = {
  "type": "dynamicView",
  "request": {
    "url": "https://api.example.com/user/1",
    "method": "get"
  },
  "template": {
    "type": "text",
    "data": "Hello, {{name}}!"
  }
};
export const dynamicViewPreviewSrc = `${PLAYGROUND_BASE_URL}/embed`;

## Overview

The `dynamicView` widget allows you to fetch data from an API and render it using a template. This powerful feature enables dynamic content rendering based on remote data sources, making it perfect for creating data-driven UIs without writing custom code.

## Features

* Fetch data from any REST API endpoint
* Apply data to templates with placeholder syntax
* Extract nested data using dot notation and array indexing
* Handle both single objects and lists of data
* Render lists of items using the itemTemplate feature
* Customize loading and error states
* Target specific data paths within complex API responses

## Properties

| Property      | Type                 | Required | Description                                                           |
| ------------- | -------------------- | -------- | --------------------------------------------------------------------- |
| request       | `StacNetworkRequest` | Yes      | API request configuration (url, method, headers, etc.)                |
| template      | `StacWidget`         | Yes      | Template to render with data from the API response                    |
| targetPath    | `String`             | No       | Path to extract specific data from the API response                   |
| resultTarget  | `String`             | No       | Key name to use when applying data to the template                    |
| loaderWidget  | `StacWidget`         | No       | Custom widget to display while loading data                           |
| errorWidget   | `StacWidget`         | No       | Custom widget to display when an error occurs                         |
| itemTemplate  | `StacWidget`         | No       | Template to render each item in a list of items from the API response |
| emptyTemplate | `StacWidget`         | No       | Template to render when the API response contains an empty list       |

## Basic Usage

<Tabs sync={false}>
  <Tab title="Dart">
    ```dart theme={null}
    StacDynamicView(
      request: StacNetworkRequest(
        url: 'https://api.example.com/user/1',
        method: Method.get,
      ),
      template: StacText(data: 'Hello, {{name}}!'),
    )
    ```
  </Tab>

  <Tab title="JSON">
    ```json theme={null}
    {
      "type": "dynamicView",
      "request": {
        "url": "https://api.example.com/user/1",
        "method": "get"
      },
      "template": {
        "type": "text",
        "data": "Hello, {{name}}!"
      }
    }
    ```
  </Tab>

  <Tab title="Preview">
    <Frame>
      <iframe
        id="stac"
        src={dynamicViewPreviewSrc}
        title="Stac Playground"
        className="w-full rounded-xl border-0"
        style={{ height: "640px" }}
        loading="lazy"
        onLoad={(event) => {
      const iframe = event.currentTarget;
      const targetOrigin = PLAYGROUND_BASE_URL;
      const message = {
        type: "stac-preview-json",
        payload: dynamicViewPreviewJson
      };

      let attempts = 0;
      const maxAttempts = 12;
      const interval = setInterval(() => {
        iframe.contentWindow?.postMessage(message, targetOrigin);
        attempts += 1;

        if (attempts >= maxAttempts) {
          clearInterval(interval);
        }
      }, 250);
    }}
      />
    </Frame>
  </Tab>
</Tabs>

## Data Placeholders

Use double curly braces `{{placeholder}}` to insert data from the API response into your template:

* For nested data, use dot notation: `{{user.address.city}}`
* For array elements, use index notation: `{{users[0].name}}` or combined path: `{{items.0.title}}`
* For array elements within objects, use combined notation: `{{data.users[2].profile.name}}`

## Examples

### User Profile Example with Loading and Error States

<CodeGroup>
  ```dart Dart theme={null}
  StacDynamicView(
    request: StacNetworkRequest(
      url: 'https://dummyjson.com/users/1',
      method: Method.get,
    ),
    loaderWidget: StacCenter(
      child: StacColumn(
        children: [
          StacText(data: 'Loading...'),
          StacCircularProgressIndicator(),
        ],
      ),
    ),
    errorWidget: StacCenter(
      child: StacText(data: 'Error fetching user profile'),
    ),
    template: StacColumn(
      children: [
        StacContainer(
          padding: StacEdgeInsets.all(16),
          child: StacColumn(
            crossAxisAlignment: StacCrossAxisAlignment.start,
            children: [
              StacImage(src: '{{image}}', width: 100, height: 100),
              StacText(
                data: '{{firstName}} {{lastName}}',
                style: StacTextStyle(fontSize: 24, fontWeight: StacFontWeight.w700),
              ),
              StacSizedBox(height: 8),
              StacText(
                data: 'Email: {{email}}',
                style: StacTextStyle(fontSize: 16, color: StacColors.grey),
              ),
              StacText(
                data: 'Phone: {{phone}}',
                style: StacTextStyle(fontSize: 16, color: StacColors.grey),
              ),
            ],
          ),
        ),
      ],
    ),
  )
  ```

  ```json JSON theme={null}
  {
    "type": "dynamicView",
    "request": {
      "url": "https://dummyjson.com/users/1",
      "method": "get"
    },
    "loaderWidget": {
      "type": "center",
      "child": {
        "type": "column",
        "children": [
          {
            "type": "text",
            "data": "Loading..."
          },
          {
            "type": "circularProgressIndicator"
          }
        ]
      }
    },
    "errorWidget": {
      "type": "center",
      "child": {
        "type": "text",
        "data": "Error fetching user profile"
      }
    },
    "template": {
      "type": "column",
      "children": [
        {
          "type": "container",
          "padding": 16,
          "child": {
            "type": "column",
            "crossAxisAlignment": "start",
            "children": [
              {
                "type": "image",
                "src": "{{image}}",
                "width": 100,
                "height": 100
              },
              {
                "type": "text",
                "style": {
                  "fontSize": 24,
                  "fontWeight": "w700"
                },
                "data": "{{firstName}} {{lastName}}"
              },
              {
                "type": "sizedBox",
                "height": 8
              },
              {
                "type": "text",
                "style": {
                  "fontSize": 16,
                  "color": "#666666"
                },
                "data": "Email: {{email}}"
              },
              {
                "type": "text",
                "style": {
                  "fontSize": 16,
                  "color": "#666666"
                },
                "data": "Phone: {{phone}}"
              }
            ]
          }
        }
      ]
    }
  }
  ```
</CodeGroup>

### List Example with itemTemplate

When the API returns a list of items, use the `itemTemplate` property to define how each item should be rendered:

<CodeGroup>
  ```dart Dart theme={null}
  StacDynamicView(
    request: StacNetworkRequest(
      url: 'https://dummyjson.com/users',
      method: Method.get,
    ),
    targetPath: 'users',
    template: StacListView(
      itemTemplate: StacListTile(
        title: StacText(data: '{{firstName}} {{lastName}}'),
        subtitle: StacText(data: '{{email}}'),
        leading: StacCircleAvatar(backgroundImage: '{{image}}'),
      ),
    ),
  )
  ```

  ```json JSON theme={null}
  {
    "type": "dynamicView",
    "request": {
      "url": "https://dummyjson.com/users",
      "method": "get"
    },
    "targetPath": "users",
    "template": {
      "type": "listView",
      "itemTemplate": {
        "type": "listTile",
        "title": {
          "type": "text",
          "data": "{{firstName}} {{lastName}}"
        },
        "subtitle": {
          "type": "text",
          "data": "{{email}}"
        },
        "leading": {
          "type": "circleAvatar",
          "backgroundImage": "{{image}}"
        }
      }
    }
  }
  ```
</CodeGroup>

### Empty State Handling

Use the `emptyTemplate` property to show a user-friendly message when the API returns an empty list:

<CodeGroup>
  ```dart Dart theme={null}
  StacDynamicView(
    request: StacNetworkRequest(
      url: 'https://api.example.com/products',
      method: Method.get,
    ),
    targetPath: 'products',
    template: StacGridView(
      crossAxisCount: 2,
      itemTemplate: StacCard(
        child: StacColumn(
          children: [
            StacImage(src: '{{image_url}}'),
            StacText(data: '{{name}}'),
            StacText(data: '\${{price}}'),
          ],
        ),
      ),
    ),
    emptyTemplate: StacCenter(
      child: StacColumn(
        mainAxisSize: StacMainAxisSize.min,
        children: [
          StacIcon(icon: 'shopping_cart', size: 64, color: StacColors.grey),
          StacSizedBox(height: 16),
          StacText(
            data: 'No products available',
            style: StacTextStyle(fontSize: 18, fontWeight: StacFontWeight.bold, color: StacColors.grey),
          ),
          StacSizedBox(height: 8),
          StacText(
            data: 'Check back later for new products!',
            style: StacTextStyle(fontSize: 14, color: StacColors.grey),
          ),
          StacSizedBox(height: 24),
          StacElevatedButton(
            child: StacText(data: 'Refresh'),
            onPressed: StacNavigateAction(route: '/refresh'),
          ),
        ],
      ),
    ),
  )
  ```

  ```json JSON theme={null}
  {
    "type": "dynamicView",
    "request": {
      "url": "https://api.example.com/products",
      "method": "get"
    },
    "targetPath": "products",
    "template": {
      "type": "gridView",
      "crossAxisCount": 2,
      "itemTemplate": {
        "type": "card",
        "child": {
          "type": "column",
          "children": [
            {
              "type": "image",
              "src": "{{image_url}}"
            },
            {
              "type": "text",
              "data": "{{name}}"
            },
            {
              "type": "text",
              "data": "${{price}}"
            }
          ]
        }
      }
    },
    "emptyTemplate": {
      "type": "center",
      "child": {
        "type": "column",
        "mainAxisSize": "min",
        "children": [
          {
            "type": "icon",
            "icon": "shopping_cart",
            "size": 64,
            "color": "#9E9E9E"
          },
          {
            "type": "container",
            "height": 16
          },
          {
            "type": "text",
            "data": "No products available",
            "style": {
              "fontSize": 18,
              "fontWeight": "bold",
              "color": "#424242"
            }
          },
          {
            "type": "container",
            "height": 8
          },
          {
            "type": "text",
            "data": "Check back later for new products!",
            "style": {
              "fontSize": 14,
              "color": "#757575"
            }
          },
          {
            "type": "container",
            "height": 24
          },
          {
            "type": "elevatedButton",
            "child": {
              "type": "text",
              "data": "Refresh"
            },
            "onPressed": {
              "actionType": "navigate",
              "route": "/refresh"
            }
          }
        ]
      }
    }
  }
  ```
</CodeGroup>

## Empty Template Behavior

The `emptyTemplate` is automatically triggered when:

1. **Direct empty array**: The API response is an empty array `[]`
2. **Empty array at target path**: The data at the specified `targetPath` is an empty array
3. **Empty arrays in nested data**: The API response contains empty arrays within nested objects

### Example API Responses that Trigger Empty Template

**Scenario 1: Direct empty array**

```json theme={null}
[]
```

**Scenario 2: Empty array at target path**

```json theme={null}
{
  "success": true,
  "data": [],
  "message": "No results found"
}
```

**Scenario 3: Empty array in nested structure**

```json theme={null}
{
  "response": {
    "users": [],
    "total": 0
  }
}
```

## Advanced Usage

### Extracting Nested Data

Use the `targetPath` property to extract specific data from complex API responses:

<CodeGroup>
  ```dart Dart theme={null}
  StacDynamicView(
    request: StacNetworkRequest(
      url: 'https://api.example.com/data',
      method: Method.get,
    ),
    targetPath: 'response.data.items',
    template: StacColumn(
      children: [
        StacText(data: 'Items loaded: {{length}}'),
      ],
    ),
  )
  ```

  ```json JSON theme={null}
  {
    "type": "dynamicView",
    "request": {
      "url": "https://api.example.com/data",
      "method": "get"
    },
    "targetPath": "response.data.items",
    "template": {
      "type": "column",
      "children": [
        {
          "type": "text",
          "data": "Items loaded: {{length}}"
        }
      ]
    }
  }
  ```
</CodeGroup>

### Using resultTarget

The `resultTarget` property allows you to specify a key name to use when applying data to the template. This is useful when you want to reference the data with a specific name in your template:

<CodeGroup>
  ```dart Dart theme={null}
  StacDynamicView(
    request: StacNetworkRequest(
      url: 'https://api.example.com/products',
      method: Method.get,
    ),
    targetPath: 'data.featured',
    resultTarget: 'product',
    template: StacCard(
      child: StacColumn(
        children: [
          StacText(data: '{{product.name}}'),
          StacText(data: 'Price: \${{product.price}}'),
        ],
      ),
    ),
  )
  ```

  ```json JSON theme={null}
  {
    "type": "dynamicView",
    "request": {
      "url": "https://api.example.com/products",
      "method": "get"
    },
    "targetPath": "data.featured",
    "resultTarget": "product",
    "template": {
      "type": "card",
      "child": {
        "type": "column",
        "children": [
          {
            "type": "text",
            "data": "{{product.name}}"
          },
          {
            "type": "text",
            "data": "Price: ${{product.price}}"
          }
        ]
      }
    }
  }
  ```
</CodeGroup>

### Custom Headers

Add custom headers to your API requests:

<CodeGroup>
  ```dart Dart theme={null}
  StacDynamicView(
    request: StacNetworkRequest(
      url: 'https://api.example.com/protected-resource',
      method: Method.get,
      headers: {
        'Authorization': 'Bearer your-token-here',
        'Content-Type': 'application/json',
      },
    ),
    template: StacText(data: 'Data loaded successfully!'),
  )
  ```

  ```json JSON theme={null}
  {
    "type": "dynamicView",
    "request": {
      "url": "https://api.example.com/protected-resource",
      "method": "get",
      "headers": {
        "Authorization": "Bearer your-token-here",
        "Content-Type": "application/json"
      }
    },
    "template": {
      "type": "text",
      "data": "Data loaded successfully!"
    }
  }
  ```
</CodeGroup>

### Array Indexing in targetPath

You can access specific array elements in the targetPath:

<CodeGroup>
  ```dart Dart theme={null}
  StacDynamicView(
    request: StacNetworkRequest(
      url: 'https://api.example.com/posts',
      method: Method.get,
    ),
    targetPath: 'data.posts[0]',
    template: StacText(data: 'Featured Post: {{title}}'),
  )
  ```

  ```json JSON theme={null}
  {
    "type": "dynamicView",
    "request": {
      "url": "https://api.example.com/posts",
      "method": "get"
    },
    "targetPath": "data.posts[0]",
    "template": {
      "type": "text",
      "data": "Featured Post: {{title}}"
    }
  }
  ```
</CodeGroup>

## Best Practices

1. Use `targetPath` to extract only the data you need from complex API responses
2. For list data, always use the `itemTemplate` property to define how each item should be rendered
3. **Always provide an `emptyTemplate`** for list-based views to handle empty API responses gracefully
4. Design empty states that are informative and actionable - include clear messaging and relevant actions like refresh buttons
5. Keep templates modular and reusable when possible
6. Use appropriate error handling in your UI design for cases when the API request fails
7. For empty states, use appropriate icons and colors that match your app's design system
8. Provide custom `loaderWidget` and `errorWidget` for better user experience
9. Use `resultTarget` when you need to reference the data with a specific name in your template
10. Keep templates modular and reusable when possible

## Limitations

* API endpoints must return JSON data
* For very large datasets, consider pagination or limiting the number of items to avoid performance issues
* Complex data transformations may require custom code outside of the template system
* Nested array access in placeholder syntax is limited to the formats shown in the examples
