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 errorsPreserved 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 arrayMethod 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?