Data Bindings Reference

WakaPAC uses the data-pac-bind attribute to connect your data to DOM elements. Bindings automatically synchronize between your data and the page - when data changes, the DOM updates, and when users interact with form elements, your data updates.

Understanding Data Binding

Binding Syntax

The data-pac-bind attribute contains comma-separated binding declarations:

<element data-pac-bind="bindingType: expression, anotherType: expression">

Each binding has two parts:

  • Binding type: What aspect of the element to control (value, visible, click, etc.)
  • Expression: An expression evaluated against your data using WakaPAC's expression language
Note: WakaPAC expressions use a simplified syntax, not full JavaScript. Supported features:
  • Array methods: includes(), indexOf(), join()
  • Property access, arithmetic, comparisons, logical operators
  • Ternary expressions
  • Not supported: function calls (except array methods above), assignments, statements

One-Way vs Two-Way Binding

One-way bindings flow data from your abstraction to the DOM. When your data changes, the DOM updates automatically:

  • visible, if, enable - Control element state
  • class, style - Control appearance
  • Standard attributes (src, href, title, etc.)

Two-way bindings flow data in both directions. DOM changes update your data, and data changes update the DOM:

  • value - For text inputs, textareas, select dropdowns
  • checked - For checkboxes

When Bindings Update

Bindings re-evaluate automatically whenever the data they reference changes. For example, if a binding uses {{ user.name }}, it updates when user.name is assigned a new value. WakaPAC tracks dependencies and only updates affected bindings.

Form Input Bindings

value - Text Inputs and Textareas

Two-way binding for text fields. Changes in the input update the data property, and changing the data property updates the input:

<div id="app">
    <input data-pac-bind="value: username" type="text">
    <textarea data-pac-bind="value: description"></textarea>

    <p>Username: {{username}}</p>
    <p>Description: {{description}}</p>
</div>

<script>
    wakaPAC('#app', {
        username: 'alice',
        description: 'Software developer'
    });
</script>

value - Select Dropdowns

Track the selected option's value:

<div id="app">
    <select data-pac-bind="value: selectedOption">
        <option value="A">Option A</option>
        <option value="B">Option B</option>
        <option value="C">Option C</option>
    </select>

    <p>You selected: {{selectedOption}}</p>
</div>

<script>
    wakaPAC('#app', {
        selectedOption: 'B'  // Pre-selects "Option B"
    });
</script>

checked - Checkboxes

Two-way binding for checkbox state (true when checked, false when unchecked):

<div id="app">
    <label>
        <input type="checkbox" data-pac-bind="checked: isActive">
        Active
    </label>

    <label>
        <input type="checkbox" data-pac-bind="checked: newsletter">
        Subscribe to newsletter
    </label>

    <p>Active: {{isActive}}, Newsletter: {{newsletter}}</p>
</div>

<script>
    wakaPAC('#app', {
        isActive: true,
        newsletter: false
    });
</script>

value - Radio Buttons

Radio buttons use value binding (not checked) because all radio buttons in a group bind to the same property. The bound property stores which radio button's value is currently selected:

<div id="app">
    <label>
        <input type="radio" name="theme" value="light" data-pac-bind="value: selectedTheme">
        Light
    </label>
    <label>
        <input type="radio" name="theme" value="dark" data-pac-bind="value: selectedTheme">
        Dark
    </label>
    <label>
        <input type="radio" name="theme" value="auto" data-pac-bind="value: selectedTheme">
        Auto
    </label>

    <p>Selected theme: {{selectedTheme}}</p>
</div>

<script>
    wakaPAC('#app', {
        selectedTheme: 'light'
    });
</script>

Display Control Bindings

visible - Toggle Visibility

Controls element visibility using CSS display property. The element remains in the DOM but is hidden when the expression evaluates to false:

<div id="app">
    <button data-pac-bind="click: toggle">Toggle</button>

    <div data-pac-bind="visible: isVisible">
        <p>This content is visible when isVisible is true</p>
    </div>

    <div data-pac-bind="visible: !isVisible">
        <p>This shows when isVisible is false</p>
    </div>
</div>

<script>
    wakaPAC('#app', {
        isVisible: true,
        toggle() {
            this.isVisible = !this.isVisible;
        }
    });
</script>

if - Conditional Rendering

Clears and restores the element's innerHTML based on the condition. The outer element remains in the DOM but becomes empty when the condition is false:

<div id="app">
    <div data-pac-bind="if: !isLoading">
        <p>Content loaded successfully</p>
    </div>
</div>

<script>
    wakaPAC('#app', {
        isLoading: false,
    });
</script>

Comment-Based Conditionals (wp-if)

Use HTML comments to conditionally render content without wrapper elements. This is ideal for tables, grids, or when you need to control multiple sibling elements together:

<div id="app">
    <!-- wp-if: !isLoading -->
    <p>Content loaded successfully</p>
    <!-- /wp-if -->
</div>

<script>
    wakaPAC('#app', {
        isLoading: false,
    });
</script>
Choosing between visible, if, and <!-- wp-if -->:
  • Use visible for frequently toggled content, preserving form state, or when you need CSS transitions
  • Use if when you already have a wrapper element and want to remove content from memory
  • Use <!-- wp-if --> for table rows, grid items, multiple siblings, or when wrapper elements would break your layout

enable - Enable/Disable Controls

Controls the disabled attribute on form elements. When the expression is true, the element is enabled; when false, it's disabled:

<div id="app">
    <input data-pac-bind="value: email" placeholder="Enter email">
    <button data-pac-bind="enable: isFormValid, click: submit">Submit</button>

    <p data-pac-bind="visible: !isFormValid">Please enter a valid email address</p>
</div>

<script>
    wakaPAC('#app', {
        email: '',

        computed: {
            isFormValid() {
                return this.email.includes('@') && this.email.length > 5;
            }
        },

        submit() {
            console.log('Form submitted:', this.email);
        }
    });
</script>

Style and Appearance Bindings

class - CSS Classes (String)

Apply CSS classes dynamically based on data. When using a string expression, the result becomes the element's class:

<div id="app">
    <div data-pac-bind="class: currentTheme">
        <p>This div has dynamic classes</p>
    </div>

    <button data-pac-bind="click: changeTheme">Change Theme</button>
</div>

<script>
    wakaPAC('#app', {
        currentTheme: 'dark',
        changeTheme() {
            this.currentTheme = this.currentTheme === 'dark' ? 'light' : 'dark';
        }
    });
</script>

class - CSS Classes (Object)

Toggle multiple classes independently using an object. Each key is a class name, each value is a boolean expression:

<div id="app">
    <div data-pac-bind="class: {active: isActive, error: hasError, 'user-premium': isPremium}">
        <p>This div has conditional classes</p>
    </div>

    <button data-pac-bind="click: toggleActive">Toggle Active</button>
    <button data-pac-bind="click: toggleError">Toggle Error</button>
</div>

<script>
    wakaPAC('#app', {
        isActive: true,
        hasError: false,
        isPremium: true,
        toggleActive() {
            this.isActive = !this.isActive;
        },
        toggleError() {
            this.hasError = !this.hasError;
        }
    });
</script>

style - Inline Styles (Object)

Apply inline CSS styles dynamically. Each key is a CSS property, each value is a string or expression:

<div id="app">
    <div data-pac-bind="style: {color: textColor, fontSize: fontSize + 'px', backgroundColor: bgColor}">
        <p>This text has dynamic styling</p>
    </div>

    <button data-pac-bind="click: increaseFontSize">Increase Font</button>
</div>

<script>
    wakaPAC('#app', {
        textColor: '#333',
        fontSize: 16,
        bgColor: '#f0f0f0',
        increaseFontSize() {
            this.fontSize += 2;
        }
    });
</script>

Attribute Bindings

Standard HTML Attributes

Bind any standard HTML attribute by using the attribute name as the binding type:

<div id="app">
    <img data-pac-bind="src: imageUrl, alt: imageDescription">
    <a data-pac-bind="href: linkUrl, title: linkTitle">Click here</a>
    <input data-pac-bind="placeholder: placeholderText, maxlength: maxChars">
</div>

<script>
    wakaPAC('#app', {
        imageUrl: 'photo.jpg',
        imageDescription: 'A beautiful photo',
        linkUrl: 'https://example.com',
        linkTitle: 'Visit our website',
        placeholderText: 'Enter your name',
        maxChars: 50
    });
</script>

List Rendering

foreach - Repeat Elements

The foreach binding repeats an element for each item in an array, automatically updating when the array changes:

<div id="app">
    <ul data-pac-bind="foreach: items">
        <li>{{item}}</li>
    </ul>
</div>

<script>
    wakaPAC('#app', {
        items: ['Apple', 'Banana', 'Cherry']
    });
</script>

foreach with Custom Item Name

Use data-pac-item to give your iteration variable a meaningful name:

<div id="app">
    <div data-pac-bind="foreach: users" data-pac-item="user">
        <p>{{user.name}} - {{user.email}}</p>
    </div>
</div>

<script>
    wakaPAC('#app', {
        users: [
            { name: 'Alice', email: 'alice@example.com' },
            { name: 'Bob', email: 'bob@example.com' }
        ]
    });
</script>

foreach with Index

WakaPAC provides the $index variable (0-based) inside foreach loops. The $ prefix prevents naming conflicts with your data properties:

<div id="app">
    <div data-pac-bind="foreach: tasks" data-pac-item="task">
        <p>{{$index + 1}}. {{task.title}}</p>
        <button data-pac-bind="click: removeTask">Remove</button>
    </div>
</div>

<script>
    wakaPAC('#app', {
        tasks: [
            { title: 'Learn WakaPAC' },
            { title: 'Build an app' },
            { title: 'Deploy to production' }
        ],

        removeTask(task, index) {
            // Click handlers receive (item, index, event) in foreach context
            this.tasks.splice(index, 1);
        }
    });
</script>

Customizing the Index Variable

You can customize the index variable name using data-pac-index:

<div data-pac-bind="foreach: items" data-pac-index="i">
    <span>Item {{i}}: {{item}}</span>
</div>

Event Handlers in foreach

Click handlers inside foreach loops automatically receive the current item and index as parameters:

methodName(item, index, event) {
    // item: the current array element
    // index: the array position (0-based)
    // event: the original DOM event
}

Nested foreach Loops

You can nest foreach loops for multi-dimensional data. Each loop has its own item and index context:

<div id="app">
    <div data-pac-bind="foreach: categories" data-pac-item="category">
        <h3>{{category.name}}</h3>
        <ul data-pac-bind="foreach: category.products" data-pac-item="product">
            <li>{{product.name}} - ${{product.price}}</li>
        </ul>
    </div>
</div>

<script>
    wakaPAC('#app', {
        categories: [
            {
                name: 'Electronics',
                products: [
                    { name: 'Laptop', price: 999 },
                    { name: 'Mouse', price: 25 }
                ]
            },
            {
                name: 'Books',
                products: [
                    { name: 'JavaScript Guide', price: 39 },
                    { name: 'Design Patterns', price: 45 }
                ]
            }
        ]
    });
</script>