Skip to content

Widget Context (xctx)

Widget Context (xctx) is a special object containing information about the widget's operating environment and state. It centrally manages container, dimensions, settings, and environmental information.

Basic Structure

typescript
interface WidgetContext {
    container: HTMLElement;        // DOM element where the widget will be rendered
    scope: any;                   // Widget scope data
    width: number;                // Widget width
    height: number;               // Widget height  
    settings: WidgetSettings;     // Widget settings
    dataSources: any[];          // Data sources
    isMobile: boolean;           // Mobile device check
    isEdit: boolean;             // In edit mode?
    isPreview?: boolean;         // In preview mode?
    isFullscreen?: boolean;      // In fullscreen mode?
    [key: string]: any;          // Additional properties
}

Basic Usage

Accessing Context Information

Context with Computed Properties

typescript
@Widget({
    selector: '.responsive-widget',
    template: `
    <div x:class:compact="isCompact" x:class:mobile="isMobileLayout">
      <h3 x:text="layoutMode">Layout</h3>
      <p x:text="message">Message</p>
    </div>
  `
})
export class ResponsiveWidget {
    @xcomputed({ dependencies: ['xctx.width'] })
    get isCompact(): boolean {
        return (this.xctx?.width || 0) < 400;
    }

    @xcomputed({ dependencies: ['xctx.isMobile'] })
    get isMobileLayout(): boolean {
        return this.xctx?.isMobile || false;
    }

    @xcomputed({ dependencies: ['xctx.width', 'xctx.isMobile'] })
    get layoutMode(): string {
        if (this.xctx?.isMobile) return 'Mobile View';
        return (this.xctx?.width || 0) < 600 ? 'Compact View' : 'Normal View';
    }

    @xcomputed({ dependencies: ['xctx.isEdit'] })
    get message(): string {
        return this.xctx?.isEdit ?
            'You are working in edit mode' :
            'You are viewing content';
    }
}

Container Operations

Accessing Container

typescript
@Widget({
    selector: '.container-widget',
    template: `
    <div class="container-operations">
      <button x:on:click="addToContainer">Add to Container</button>
      <button x:on:click="checkContainer">Check Container</button>
      <p x:text="containerInfo">Container info</p>
    </div>
  `
})
export class ContainerWidget {
    @xproperty()
    containerInfo: string = '';

    addToContainer(): void {
        const container = this.xctx?.container;
        if (container && container.isConnected) {
            const newElement = document.createElement('div');
            newElement.textContent = `New element - ${new Date().toLocaleTimeString()}`;
            newElement.className = 'dynamic-item';
            container.appendChild(newElement);

            this.containerInfo = `Element added: ${container.children.length} children`;
        }
    }

    checkContainer(): void {
        const container = this.xctx?.container;
        if (container) {
            this.containerInfo = `
        Tag: ${container.tagName}
        ID: ${container.id || 'none'}
        Children: ${container.children.length}
      `;
        }
    }
}

Settings Management

Using Widget Settings

typescript
interface MyWidgetSettings {
    theme: 'light' | 'dark';
    language: string;
    autoRefresh: boolean;
}

@Widget({
    selector: '.settings-widget',
    template: `
    <div x:class:dark-theme="isDarkTheme">
      <h3>Widget Settings</h3>
      <p>Theme: <span x:text="currentTheme">-</span></p>
      <p>Language: <span x:text="currentLanguage">-</span></p>
      <p>Auto Refresh: <span x:text="autoRefreshStatus">-</span></p>
      <button x:on:click="toggleTheme">Toggle Theme</button>
    </div>
  `
})
export class SettingsWidget implements OnWidgetReady {
    @xproperty()
    currentTheme: string = 'light';

    @xproperty()
    currentLanguage: string = 'tr';

    @xcomputed({ dependencies: ['currentTheme'] })
    get isDarkTheme(): boolean {
        return this.currentTheme === 'dark';
    }

    @xcomputed({ dependencies: ['xctx.settings.autoRefresh'] })
    get autoRefreshStatus(): string {
        const settings = this.xctx?.settings as MyWidgetSettings;
        return settings?.autoRefresh ? 'On' : 'Off';
    }

    onWidgetReady(): void {
        const settings = this.xctx?.settings as MyWidgetSettings;
        if (settings) {
            this.currentTheme = settings.theme || 'light';
            this.currentLanguage = settings.language || 'tr';
        }
    }

    toggleTheme(): void {
        if (this.xctx?.settings) {
            const newTheme = this.currentTheme === 'light' ? 'dark' : 'light';
            this.currentTheme = newTheme;
            (this.xctx.settings as MyWidgetSettings).theme = newTheme;
        }
    }
}

Direct Context Usage in Template

Binding with xctx

typescript
@Widget({
    selector: '.direct-context-widget',
    template: `
    <div class="context-bindings">
      <!-- Direct access to context values -->
      <p>Width: <span x:text="xctx.width || 0">0</span>px</p>
      <p>Height: <span x:text="xctx.height || 0">0</span>px</p>
      <p>Mobile: <span x:text="xctx.isMobile ? 'Yes' : 'No'">No</span></p>
      
      <!-- Conditional rendering -->
      <div x:class:visible="xctx.isEdit" class="edit-panel">
        <h4>Editing Tools</h4>
        <button x:on:click="save">Save</button>
      </div>
      
      <!-- Responsive layout -->
      <div 
        x:class:mobile-layout="xctx.isMobile" 
        x:class:desktop-layout="!xctx.isMobile">
        <p x:text="layoutMessage">Layout</p>
      </div>
    </div>
  `,
    styles: [`
    .edit-panel {
      display: none;
      background: #fff3cd;
      padding: 15px;
      border-radius: 6px;
    }
    .edit-panel.visible {
      display: block;
    }
    .mobile-layout { font-size: 14px; }
    .desktop-layout { font-size: 16px; }
  `]
})
export class DirectContextWidget {
    @xcomputed({ dependencies: ['xctx.isMobile'] })
    get layoutMessage(): string {
        return this.xctx?.isMobile ?
            'Mobile optimization active' :
            'Desktop full features';
    }

    save(): void {
        console.log('Changes saved');
    }
}

Context Updates

Dynamic Context Updates

typescript
@Widget({
    selector: '.update-context-widget',
    template: `
    <div class="update-controls">
      <h3>Context Update</h3>
      
      <div class="control-group">
        <label>Custom Data:</label>
        <input type="text" x:model="newData">
        <button x:on:click="updateCustomData">Update</button>
      </div>
      
      <div class="control-group">
        <button x:on:click="toggleFullscreen">Fullscreen</button>
        <button x:on:click="refreshContext">Refresh</button>
      </div>
      
      <div class="context-display">
        <pre x:text="contextSummary">Loading context info...</pre>
      </div>
    </div>
  `
})
export class UpdateContextWidget implements OnWidgetReady {
    @xproperty()
    newData: string = '';

    @xproperty()
    contextSummary: string = '';

    onWidgetReady(): void {
        this.refreshContext();
    }

    updateCustomData(): void {
        if (this.xctx && this.newData) {
            // Adding custom data to context
            this.xctx.customData = this.newData;
            this.newData = '';
            this.refreshContext();
        }
    }

    toggleFullscreen(): void {
        if (this.xctx) {
            this.xctx.isFullscreen = !this.xctx.isFullscreen;
            this.refreshContext();
        }
    }

    refreshContext(): void {
        if (this.xctx) {
            this.contextSummary = `
Width: ${this.xctx.width || 0}px
Height: ${this.xctx.height || 0}px
Mobile: ${this.xctx.isMobile ? 'Yes' : 'No'}
Edit Mode: ${this.xctx.isEdit ? 'Yes' : 'No'}
Fullscreen: ${this.xctx.isFullscreen ? 'Yes' : 'No'}
      `.trim();
        }
    }
}

Best Practices

1. Null Safety

typescript
// Always check xctx existence
if (this.xctx?.container) {
    // Safe context operations
}

// Use default values
const width = this.xctx?.width || 0;
const isMobile = this.xctx?.isMobile || false;

2. Responsive Design

typescript
@xcomputed({ dependencies: ['xctx.width'] })
get isCompactMode(): boolean {
    return (this.xctx?.width || 0) < 400;
}

@xcomputed({ dependencies: ['xctx.isMobile', 'xctx.width'] })
get deviceType(): string {
    if (this.xctx?.isMobile) return 'mobile';
    return (this.xctx?.width || 0) < 768 ? 'tablet' : 'desktop';
}

3. Container Safety

typescript
// Safety check in container operations
private safeContainerOperation(): void {
    const container = this.xctx?.container;
    if (container && container.isConnected) {
    // Safe DOM operations
}
}

4. Settings Management

typescript
// Use settings in a type-safe way
interface MySettings {
    option1: string;
    option2: boolean;
}

private getSettings(): MySettings | undefined {
    return this.xctx?.settings as MySettings;
}

updateSetting(key: keyof MySettings, value: any): void {
    const settings = this.getSettings();
    if (settings) {
        settings[key] = value;
    }
}

Summary

Widget Context (xctx) features:

Container Reference - Direct access to DOM container
Dimension Information - width, height tracking
Responsive Behavior - isMobile, device detection
Mode Control - isEdit, isPreview, isFullscreen
Settings Configuration - Managing widget settings
Template Binding - Direct xctx usage
Dynamic Updates - Runtime context changes

Context is a powerful and flexible system that centrally manages the widget's operating environment.