What's New With 2.0

08/30/2022

New Features

File Upload Support

CBWIRE 2.0 introduces comprehensive file upload capabilities with built-in handling for single and multiple files.

// wires/FileUploader.cfc
component extends="cbwire.models.Component" {
    data = {
        "uploadedFile" = "",
        "uploadedFiles" = [],
        "uploadProgress" = 0
    };
    
    function processUpload() {
        if (structKeyExists(data, "uploadedFile") && len(data.uploadedFile)) {
            // Handle single file upload
            var uploadPath = expandPath("./uploads/");
            fileMove(data.uploadedFile, uploadPath & data.uploadedFile.getClientFileName());
            
            data.uploadProgress = 100;
        }
    }
    
    function processMultipleUploads() {
        if (arrayLen(data.uploadedFiles)) {
            var uploadPath = expandPath("./uploads/");
            
            for (var file in data.uploadedFiles) {
                fileMove(file, uploadPath & file.getClientFileName());
            }
            
            data.uploadProgress = 100;
        }
    }
}
<!-- wires/fileUploader.cfm -->
<cfoutput>
<div class="upload-container">
    <form wire:submit="processUpload">
        <label for="file">Choose File:</label>
        <input type="file" wire:model="uploadedFile" id="file">
        
        <cfif uploadProgress GT 0>
            <div class="progress">
                <div class="progress-bar" style="width: #uploadProgress#%">#uploadProgress#%</div>
            </div>
        </cfif>
        
        <button type="submit">Upload File</button>
    </form>
    
    <form wire:submit="processMultipleUploads">
        <label for="files">Choose Multiple Files:</label>
        <input type="file" wire:model="uploadedFiles" id="files" multiple>
        <button type="submit">Upload Files</button>
    </form>
</div>
</cfoutput>

Component Testing

Write comprehensive unit tests for your CBWIRE components with the new testing framework.

// tests/specs/integration/ComponentTest.cfc
component extends="cbwire.testing.BaseWireSpec" {
    
    function testCounterComponent() {
        var comp = visitComponent("Counter")
            .assertSee("0")
            .call("increment")
            .assertSee("1")
            .call("increment")
            .assertSee("2")
            .call("reset")
            .assertSee("0");
    }
    
    function testFormSubmission() {
        var comp = visitComponent("ContactForm")
            .set("name", "John Doe")
            .set("email", "[email protected]")
            .set("message", "Test message")
            .call("submitForm")
            .assertSee("Thank you")
            .assertDontSee("Please fill");
    }
    
    function testDataPersistence() {
        var comp = visitComponent("UserProfile", { "userId": 123 })
            .assertSee("John Doe")
            .set("firstName", "Jane")
            .call("updateProfile")
            .assertSee("Jane Doe")
            .assertDontSee("John Doe");
    }
}

Custom Wires Directory

Override the default wires folder location to organize components according to your application structure.

// config/ColdBox.cfc
moduleSettings = {
    "cbwire" = {
        "wiresDirectory" = "/custom/components/path"
    }
};
// Alternative: Set custom location per component
component extends="cbwire.models.Component" {
    this.template = "/custom/templates/MyComponent.cfm";
}

Skip Rendering with noRender()

Prevent template rendering when you only need to update data without returning HTML.

// wires/APIHandler.cfc
component extends="cbwire.models.Component" {
    data = {
        "status" = "idle",
        "result" = {}
    };
    
    function processAPICall() {
        data.status = "processing";
        
        try {
            data.result = callExternalAPI();
            data.status = "success";
        } catch (any e) {
            data.status = "error";
            data.result = { "error" = e.message };
        }
        
        // Skip template rendering for AJAX-only updates
        noRender();
    }
}

Dirty Property Tracking

Track which properties have changed since the last render for optimized updates.

// wires/FormTracker.cfc
component extends="cbwire.models.Component" {
    data = {
        "formData" = {},
        "hasChanges" = false,
        "changedFields" = []
    };
    
    function onUpdated() {
        // Track which properties are dirty
        var dirtyProps = getDirtyProperties();
        
        if (arrayLen(dirtyProps)) {
            data.hasChanges = true;
            data.changedFields = dirtyProps;
        }
    }
    
    function saveChanges() {
        if (data.hasChanges) {
            // Only save changed fields
            for (var field in data.changedFields) {
                updateFieldInDatabase(field, data.formData[field]);
            }
            
            data.hasChanges = false;
            data.changedFields = [];
        }
    }
}

Computed Property Optimization

Computed properties now run only once per request during rendering for better performance.

// wires/Dashboard.cfc
component extends="cbwire.models.Component" {
    data = {
        "users" = [],
        "orders" = []
    };
    
    // This expensive calculation runs only once per render
    function getTotalRevenue() {
        var total = 0;
        
        for (var order in data.orders) {
            total += order.amount;
        }
        
        return dollarFormat(total);
    }
    
    // This also runs once and caches the result
    function getUserStats() {
        return {
            "total" = arrayLen(data.users),
            "active" = data.users.filter(function(user) {
                return user.status == "active";
            }).len(),
            "premium" = data.users.filter(function(user) {
                return user.isPremium;
            }).len()
        };
    }
}

Dependency Injection Support

Components now support ColdBox's dependency injection system.

// wires/UserManager.cfc
component extends="cbwire.models.Component" {
    
    property name="userService" inject="UserService";
    property name="emailService" inject="EmailService";
    property name="settings" inject="coldbox:moduleSettings:cbwire";
    
    data = {
        "users" = [],
        "selectedUser" = {}
    };
    
    function mount() {
        data.users = userService.getAllUsers();
    }
    
    function sendWelcomeEmail(userId) {
        var user = userService.getUser(userId);
        emailService.sendWelcomeEmail(user.email, user.firstName);
    }
}

Enhanced Turbo Support

Enable single-page application functionality with improved Turbo integration.

// config/ColdBox.cfc
moduleSettings = {
    "cbwire" = {
        "enableTurbo" = true,
        "moduleRootURI" = "/custom/cbwire/path"
    }
};

Enhancements

Template Path Flexibility

Set custom template paths for components using the this.template property.

// wires/CustomComponent.cfc
component extends="cbwire.models.Component" {
    this.template = "/custom/views/special-template.cfm";
    
    data = {
        "content" = "Custom template content"
    };
}

Null Value Support

Data properties now properly support null as a valid value.

// wires/UserProfile.cfc
component extends="cbwire.models.Component" {
    data = {
        "avatar" = null,  // Null is now a valid value
        "bio" = null,
        "website" = null
    };
    
    function clearAvatar() {
        data.avatar = null;  // Explicitly set to null
    }
}

Livewire JavaScript Upgrade

Updated to Livewire JS v2.10.6 for improved client-side functionality and bug fixes.

Performance Optimizations

  • Disabled browser caching for XHR responses to ensure fresh data

  • Trimmed XHR payload by removing unnecessary data

  • Moved internal methods to Engine object to prevent naming conflicts

  • Added security by rejecting XHR requests without proper headers

Bug Fixes

Component State Management

  • Fixed reset() errors: Calling reset("someProperty") no longer causes errors

  • Preserved component IDs: Component IDs are now preserved across renders to avoid DOM diffing issues

  • Better parameter handling: Fixed missing parameters in update method calls

Browser Compatibility

  • Fixed back button issues: Browser back button now works correctly with CBWIRE components

  • Improved navigation: Better handling of browser history and navigation states

Data Integrity

  • Parameter validation: Ensured params is properly passed as an array

  • Method parameter handling: Fixed missing parameters in component method calls

Breaking Changes

This is a major version release with some breaking changes:

Component Structure

Some internal method names have changed to prevent conflicts. If you were extending or overriding internal CBWIRE methods, you may need to update your code.

XHR Security

XHR requests now require the X-Livewire header. This improves security but may affect custom AJAX implementations.

Template Resolution

The default template resolution has been improved. If you have custom template path logic, verify it still works correctly with the new resolution system.

Last updated

Was this helpful?