Data Properties

Data Properties hold the state of your component and are defined with a data structure. Each data property is assigned a default value and is automatically synchronized between server and client.

Data properties are reactive - when an action modifies a property, CBWIRE automatically re-renders only the affected parts of your template. They can hold strings, numbers, booleans, dates, arrays, and structures, and are directly accessible in templates without special syntax.

//./wires/SomeComponent.bx
class extends="cbwire.models.Component" {
    data = {
        "propertyName": "defaultValue"
    };
}

Accessing From Actions

Using the data structure, you can access data properties from within your component actions.

// Data properties
data = {
    "time": now()
}; 
   
// Action
function updateTime(){
    data.time = now();
}

Accessing From Templates

You can access data properties within your templates using #propertyName#.

<bx:output>
    <div>
        <h1>Current time</h1>
        <div>#time#</div>
        <button wire:click="updateTime">Update</button>
    </div>
</bx:output>

Nested Properties

Organize related data using nested structures and access them with dot notation. This keeps your data organized hierarchically instead of flattening everything into top-level properties.

// wires/UserProfile.bx
class extends="cbwire.models.Component" {
    data = {
        "user": {
            "name": {
                "first": "John",
                "last": "Doe"
            },
            "contact": {
                "email": "[email protected]",
                "phone": "555-1234"
            },
            "preferences": {
                "theme": "dark",
                "notifications": true
            }
        }
    };
}

Accessing in Templates

Reference nested properties using dot notation in wire:model and other directives:

<!-- wires/userProfile.bxm -->
<bx:output>
<form wire:submit="saveProfile">
    <input type="text" wire:model="user.name.first" placeholder="First Name">
    <input type="text" wire:model="user.name.last" placeholder="Last Name">
    <input type="email" wire:model="user.contact.email" placeholder="Email">
    <input type="tel" wire:model="user.contact.phone" placeholder="Phone">

    <select wire:model="user.preferences.theme">
        <option value="light">Light</option>
        <option value="dark">Dark</option>
    </select>

    <label>
        <input type="checkbox" wire:model="user.preferences.notifications">
        Enable notifications
    </label>

    <button type="submit">Save Profile</button>
</form>
</bx:output>

Accessing in Actions

Use dot notation to access and modify nested properties in your component methods:

// wires/UserProfile.bx
class extends="cbwire.models.Component" {
    data = {
        "user": {
            "name": {
                "first": "John",
                "last": "Doe"
            },
            "contact": {
                "email": "[email protected]"
            }
        }
    };

    function saveProfile() {
        // Access nested properties
        var fullName = data.user.name.first & " " & data.user.name.last;

        // Modify nested properties
        data.user.contact.email = data.user.contact.email.trim();

        // Save to database
        userService.update( data.user );
    }

    function updateTheme( theme ) {
        data.user.preferences.theme = theme;
    }
}

Lifecycle Hooks

Lifecycle hooks for nested properties use underscores instead of dots. A property path like user.name.first triggers onUpdateuser_name_first():

// wires/UserProfile.bx
class extends="cbwire.models.Component" {
    data = {
        "user": {
            "contact": {
                "email": "[email protected]"
            }
        }
    };

    function onUpdateuser_contact_email( value, oldValue ) {
        // Triggered when user.contact.email changes
        writeLog( "Email changed from #oldValue# to #value#" );

        // Validate email format
        if ( !isValid( "email", value ) ) {
            data.user.contact.email = oldValue;
            addError( "user.contact.email", "Please enter a valid email address" );
        }
    }
}

Missing nested keys are created automatically. If data.user doesn't have a preferences key, setting data.user.preferences.theme = "dark" creates the structure automatically.

Resetting Properties

You can reset all data properties to their original default value inside your actions using reset().

data = {
    "time": now()
};

function resetTime(){
    reset();
}

You can reset individual, some, or all data properties.

function resetForm() {
    reset( "message" ); // resets 'message' data property
    reset( [ "message", "anotherprop" ] ); // reset multiple properties at once
    reset(); // resets all properties
}

You can also reset all properties EXCEPT the properties you pass.

function resetForm() {
    resetExcept( "email" );
    resetExcept( [ "email", "phoneNumber" ] );
}

Locked Properties

Locked properties prevent client-side modifications to sensitive data like user IDs, roles, or permissions. Define a locked variable to protect specific properties from wire:model and other client interactions. CBWIRE throws an exception if locked properties are modified from the client.

Single Property

// wires/UserProfile.bx
class extends="cbwire.models.Component" {
    // Lock single property
    locked = "userId";
    
    data = {
        "userId": 123,
        "name": "John Doe",
        "email": "[email protected]",
        "isActive": true
    };
    
    function updateProfile() {
        // Can modify name, email, isActive
        // Cannot modify userId - it's locked
    }
}

Multiple Properties

// wires/AdminPanel.bx
class extends="cbwire.models.Component" {
    // Lock multiple properties
    locked = ["userId", "role", "permissions", "accountType"];
    
    data = {
        "userId": 123,
        "name": "Jane Admin",
        "email": "[email protected]",
        "role": "administrator",
        "permissions": ["read", "write", "delete", "admin"],
        "accountType": "premium",
        "lastLogin": now(),
        "theme": "dark"
    };
    
    function updateSettings() {
        // Can modify: name, email, lastLogin, theme
        // Cannot modify: userId, role, permissions, accountType
        data.lastLogin = now();
        data.theme = "light";
    }
}

Template Usage

Locked properties can be displayed but not modified through form inputs:

<!-- wires/adminPanel.bxm -->
<bx:output>
<div>
    <h1>User Profile</h1>
    
    <!-- Display locked properties (read-only) -->
    <div class="readonly-info">
        <p><strong>User ID:</strong> #userId#</p>
        <p><strong>Role:</strong> #role#</p>
        <p><strong>Account Type:</strong> #accountType#</p>
    </div>
    
    <!-- Form with editable properties -->
    <form wire:submit="updateSettings">
        <!-- These inputs work normally -->
        <input type="text" wire:model="name" placeholder="Name">
        <input type="email" wire:model="email" placeholder="Email">
        
        <select wire:model="theme">
            <option value="light">Light</option>
            <option value="dark">Dark</option>
        </select>
        
        <!-- These would throw an exception if attempted -->
        <!-- <input type="hidden" wire:model="userId"> ❌ -->
        <!-- <input type="text" wire:model="role"> ❌ -->
        
        <button type="submit">Update Profile</button>
    </form>
</div>
</bx:output>

Common Use Cases

  • User Management: Lock userId, role, permissions

  • E-commerce: Lock product IDs, prices, inventory counts

  • Financial: Lock account numbers, balances, transaction IDs

  • Content: Lock author IDs, creation dates, publication status

Locked properties only prevent client-side modifications. Server-side code in your action methods can still modify locked properties when necessary.

Last updated

Was this helpful?