---
sidebar_position: 2
---
# Data Loading

This guide explains the data loading mechanism in Myop components, from initial state to fully rendered UI.

## Loading Lifecycle

### Step 1: Initial State (Loader Visible)

When the component first loads, it shows a loading indicator while waiting for data:

```css
/* Loader is visible by default */
#loader-container {
    display: flex;
}

/* App is hidden by default */
#app-root {
    opacity: 0;
}
```

At this point:
- **Loader is visible** (`#loader-container` shown)
- **App is hidden** (`#app-root` has `opacity: 0`)
- Component waits for data via `window.myop_init_interface()`

### Step 2: Host Provides Data

The host application calls `window.myop_init_interface()` with data:

```javascript
// From the host application
window.myop_init_interface({
    components: [
        {
            id: "comp-1",
            name: "AuthService",
            developerName: "Alice Green",
            lastEditedDate: "2024-03-15T10:30:00.000Z",
            lastVersionName: "v1.2.3",
            environments: ["prod", "dev"],
            tags: ["backend", "security"]
        },
        // ... more components
    ]
});
```

### Step 3: Component Processes Data

Inside `myop_init_interface()`, the component:

1. **Stores and transforms data**
2. **Extracts values for filters/aggregations**
3. **Renders dynamic elements**
4. **Attaches event listeners**
5. **Hides loader and shows app**

```javascript
function initializeComponent(componentsData) {
    // 1. Store and transform data
    allComponentsState = componentsData.map(c => ({
        ...c,
        lastEditedDate: new Date(c.lastEditedDate)
    }));

    // 2. Extract unique values for filters
    const allDevelopers = [...new Set(
        allComponentsState.map(c => c.developerName)
    )].sort();

    // 3. Render filter groups dynamically
    renderFilterGroup('Developer', allDevelopers, 'developers');

    // 4. Attach event listeners (only once)
    if (!isInitialized) {
        attachSearchListener();
        attachFilterListeners();
        isInitialized = true;
    }

    // 5. Render the component list
    applyFiltersAndRender();

    // 6. Hide loader and show app
    hideLoader();
}
```

### Step 4: Component Becomes Interactive

After initialization, the component is fully interactive:

```javascript
function hideLoader() {
    document.getElementById('loader-container').style.display = 'none';
    document.getElementById('app-root').style.opacity = '1';
}
```

## Data Transformation

### Parsing Dates

Always parse date strings during initialization for consistent handling:

```javascript
function initializeComponent(data) {
    allComponentsState = data.components.map(component => ({
        ...component,
        // Parse ISO date string to Date object once
        lastEditedDate: new Date(component.lastEditedDate),
        createdDate: new Date(component.createdDate)
    }));
}
```

### Normalizing Data

Normalize data structures for easier rendering:

```javascript
function normalizeComponent(raw) {
    return {
        id: raw.id,
        name: raw.name || 'Unnamed',
        description: raw.description || '',
        status: raw.status?.toLowerCase() || 'unknown',
        tags: Array.isArray(raw.tags) ? raw.tags : [],
        metadata: {
            author: raw.developerName || raw.author || 'Unknown',
            version: raw.lastVersionName || raw.version || '1.0.0',
            updatedAt: new Date(raw.lastEditedDate || raw.updatedAt)
        }
    };
}
```

## Updating Component Data

### Full Data Replacement

Replace all data with a new dataset:

```javascript
window.myop_init_interface = function(data) {
    if (data && data.components) {
        // Full replacement
        initializeComponent(data);
    }
};
```

### Action-Based Updates

Support incremental updates with action types:

```javascript
window.myop_init_interface = function(input) {
    // No input = getter mode
    if (!input) {
        return { components: allComponentsState };
    }

    // Action-based update
    if (input.action) {
        switch (input.action) {
            case 'setData':
                initializeComponent(input.payload);
                break;
            case 'addItem':
                addComponent(input.payload);
                break;
            case 'removeItem':
                removeComponent(input.payload.id);
                break;
            case 'updateItem':
                updateComponent(input.payload);
                break;
        }
        return;
    }

    // Direct data initialization
    initializeComponent(input);
};

function addComponent(component) {
    allComponentsState.push(normalizeComponent(component));
    applyFiltersAndRender();
}

function removeComponent(id) {
    allComponentsState = allComponentsState.filter(c => c.id !== id);
    applyFiltersAndRender();
}

function updateComponent(updated) {
    const index = allComponentsState.findIndex(c => c.id === updated.id);
    if (index !== -1) {
        allComponentsState[index] = {
            ...allComponentsState[index],
            ...normalizeComponent(updated)
        };
        applyFiltersAndRender();
    }
}
```

## Loading States

### Skeleton Loading

For better UX, show skeleton placeholders:

```html
<div id="app-root">
    <div class="skeleton-list">
        <div class="skeleton-item">
            <div class="skeleton-line" style="width: 60%"></div>
            <div class="skeleton-line" style="width: 40%"></div>
        </div>
        <div class="skeleton-item">
            <div class="skeleton-line" style="width: 55%"></div>
            <div class="skeleton-line" style="width: 45%"></div>
        </div>
    </div>
    <div class="actual-content" style="display: none;">
        <!-- Actual content rendered here -->
    </div>
</div>
```

```css
.skeleton-item {
    padding: 16px;
    border-bottom: 1px solid #eee;
}

.skeleton-line {
    height: 16px;
    background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
    background-size: 200% 100%;
    animation: shimmer 1.5s infinite;
    border-radius: 4px;
    margin-bottom: 8px;
}

@keyframes shimmer {
    0% { background-position: 200% 0; }
    100% { background-position: -200% 0; }
}
```

### Error States

Handle loading errors gracefully:

```javascript
window.myop_init_interface = function(data) {
    if (!data) {
        return { components: allComponentsState };
    }

    // Handle error state
    if (data.error) {
        showErrorState(data.error.message);
        return;
    }

    initializeComponent(data);
};

function showErrorState(message) {
    const loaderContainer = document.getElementById('loader-container');
    const appRoot = document.getElementById('app-root');

    loaderContainer.style.display = 'none';
    appRoot.innerHTML = `
        <div class="error-state">
            <div class="error-icon">!</div>
            <h3>Failed to load</h3>
            <p>${escapeHtml(message)}</p>
            <button onclick="window.myop_cta_handler('retry')">
                Try Again
            </button>
        </div>
    `;
    appRoot.style.opacity = '1';
}
```

### Empty States

Show meaningful empty states:

```javascript
function renderItems(items) {
    const container = document.querySelector('.item-list');

    if (items.length === 0) {
        container.innerHTML = `
            <div class="empty-state">
                <div class="empty-icon">📭</div>
                <h3>No items found</h3>
                <p>Try adjusting your filters or create a new item.</p>
                <button onclick="window.myop_cta_handler('create_new')">
                    Create New
                </button>
            </div>
        `;
        return;
    }

    container.innerHTML = items.map(renderItem).join('');
}
```

## Data Flow Diagram

```
┌─────────────────────────────────────────────────────────────┐
│                    HOST APPLICATION                          │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  1. MyopContainer renders component                  │   │
│  │  2. onReady callback fires                           │   │
│  │  3. Set myop_cta_handler                             │   │
│  │  4. Fetch data from API                              │   │
│  │  5. Call myop_init_interface(data)                   │   │
│  └────────────────────────┬────────────────────────────┘   │
└───────────────────────────│─────────────────────────────────┘
                            │
                            ▼
┌─────────────────────────────────────────────────────────────┐
│                    MYOP COMPONENT                            │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  window.myop_init_interface(data):                   │   │
│  │    1. Store data in private state                    │   │
│  │    2. Transform data (parse dates, normalize)        │   │
│  │    3. Render component UI                            │   │
│  │    4. Attach event listeners (once)                  │   │
│  │    5. Hide loader, show app                          │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                              │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  User Interaction:                                   │   │
│  │    → Call window.myop_cta_handler('action', payload) │   │
│  └────────────────────────┬────────────────────────────┘   │
└───────────────────────────│─────────────────────────────────┘
                            │
                            ▼
┌─────────────────────────────────────────────────────────────┐
│                    HOST APPLICATION                          │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  myop_cta_handler receives event:                    │   │
│  │    1. Parse action_id                                │   │
│  │    2. Handle action (navigate, open modal, etc.)     │   │
│  └─────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────┘
```

## Next Steps

- Set up [Mock Data](/docs/learnMyop/html-components/mock-data) for development
- Learn the full [Public API](/docs/learnMyop/html-components/public-api) reference
- See [Host Integration](/docs/learnMyop/html-components/host-integration) examples
