Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...


With CommandBox, you can start building reactive CFML apps in seconds.
Call an action immediately once your Wire is first rendered.
Prefetch state changes when the user mouses over an HTML element. Fantastico!
Toggle UI elements when the user is offline or online. Groovy!
https://yourapp.com/search-articles?search=some+string<div>
<input wire:model="search" type="search" placeholder="Search articles...">
</div><div wire:init="loadTasks">
<ul>
<cfloop array="#args.tasks#" index="task">
<li>#task#</li>
</cfloop>
</ul>
</div>component extends="cbwire.models.Component" {
property name="taskService" inject="TaskService@myapp";
data = {
"tasks": []
};
function loadTasks(){
data.tasks = taskService.asMemento().get();
}
}<div>
<button wire:click.prefetch="togglePreview">Show Preview</button>
<cfif args.showPreview>
<!--- Preview goes here --->
</cfif>
</div>component extends="cbwire.models.Component"{
data = {
"showPreview": false
};
function togglePreview(){
data.showPreview = true;
}
}<div wire:offline><!-- Oh no, you're offline --></div><div wire:offline.class="online" class="online"></div><div wire:offline.class.remove="im-online" class="im-online"></div>component extends="cbwire.models.Component" {
data = {
"search": ""
};
queryString = [ "search" ];
}box install cbwirebox install cbwire@be<!--- ./layouts/Main.cfm --->
<cfoutput>
<!DOCTYPE html>
<html lang="en">
<head>
<title>CBWIRE Example</title>
#wireStyles()#
</head>
<body>
<!--- JavasScript references below --->
#wireScripts()#
</body>
</html>
</cfoutput><!--- ./layouts/Main.cfm --->
<body>
<!--- Insert our task list wire here --->
#wire( "TaskList" )#
<!--- JavasScript references below --->
#wireScripts()#
</body><!--- ./views/someview.cfm --->
<cfoutput>
<div>#wire( "TaskList" )#</div>
</cfoutput>mkdir cbwire-demo
cd cbwire-demo
box coldbox create app
box install cbwire@be
box server start<!--- ./layouts/Main.cfm --->
<cfoutput>
<!doctype html>
<html>
<head>
#wireStyles()#
</head>
<body>
#wire( "Counter" )#
#wireScripts()#
</body>
</html>
</cfoutput>
// ./wires/Counter.cfc
component extends="cbwire.models.Component" {
// Data Properties
data = {
"counter": 0
};
// Actions
function increment(){
data.counter += 1;
}
}
<!--- ./views/wires/counter.cfm --->
<cfoutput>
<div>
<div>Count: #args.counter#</div>
<button wire:click="increment">
+
</button>
</div>
</cfoutput>Your Wire's HTML. Simple as that. Honestly.
Wires are reactive UI elements you create. They include a powerful feature-set provided by CBWIRE.
You can emit events from both your Wires and JavaScript. Superb!
Alter CBWIRE's behavior with these nifty configuration options.
Just as with ColdBox, you can inject your dependencies using WireBox.
component extends="cbwire.models.Component" {
// Property injection
property name="storage" inject="cbfs:disks:temp";
// Setter injection
function setStorage() inject="cbfs:disks:temp" {};
// Actions
function someAction() {
// Use the storage object
storage.create( "log.txt", "CBWIRE rocks!" );
// Use getInstance() to get objects.
var defaultStorage = getInstance( "cbfs:disks:default" );
}
}// File: ./config/ColdBox.cfc
component{
function configure() {
moduleSettings = {
cbwire = {
"enableTurbo": false,
"maxUploadSeconds": 5 * 60, // 5 minutes
"throwOnMissingSetterMethod" : false,
"trimStringValues": false,
"wiresLocation": "myWires",
"useComputedPropertiesProxy": false
}
};
}
}
component extends="cbwire.models.Component" {
property name="storage" inject="cbfs:disks:temp";
function onDIComplete(){
storage.create( "log.txt", "Dependency Injection Complete!" );
}
}component extends="cbwire.models.Component"{
this.constraints = {
"task": { required: true }
};
// Data Properties
data = {
"task": ""
};
}component extends="cbwire.models.Component"{
// Action
function addTask() {
var result = validate(); // ValidateResult object
if ( !result.hasErrors() ) {
queryExecute( ... );
}
}
}component extends="cbwire.models.Component"{
// Action
function addTask() {
validateOrFail();
queryExecute( ... );
}
}component extends="cbwire.models.Component"{
// Action
function addTask() {
var data = { "email": "cbwire@rocks.com" };
var validationManager = getValidationManager();
var result = validationManager.validate(
target=data,
constraints={
"email": { required: true, type: "email" }
}
);
}
}<cfoutput>
<div>
<input wire:model="task" type="text">
<button wire:click="addTask">Add</button>
<cfif args.validation.hasErrors( "task" )>
<cfloop array="#args.validation.getAllErrors( "task" )#" index="error">
<div>#error#</div>
</cfloop>
</cfif>
</div>
</cfoutput>component extends="cbwire.models.Component" {
// No template defined.
}component extends="cbwire.models.Component" {
template = "wires/tasklist"; // This will look for ./views/wires/tasklist.cfm
// template = "path/to/tasklist"; <--- Can use folders
// template = "tasklist.cfm"; <--- Can use .cfm if you like
}component extends="cbwire.model.Component"{
// Action
function updateSession(){
// prevent UI updating
noRender();
}
}<!--- GOOD --->
<cfoutput>
<div>
<button wire:click="addTask">Add Task</button>
</div>
</cfoutput>
<!--- BAD --->
<cfoutput>
<div>
<button wire:click="addTask">Add Task</button>
</div>
<div>
<h1>Tasks</h1>
</div>
</cfoutput>// File: wires/TaskList.cfc
component extends="cbwire.models.Component" {
// Data properties
data = {
"task": "",
"tasks": []
};
// Computed properties
computed = {
"counter": function() {
return arrayLen( data.tasks );
}
};
// Listeners
listeners = {
"taskAdded": "sendEmail"
};
// Action
function addTask(){
data.tasks.append( data.task );
this.emit( "taskAdded", data.task );
}
}<!--- /views/wires/tasklist.cfm --->
<cfoutput>
<div>
<div>Number of tasks: #args.computed.counter()#</div>
<div><input wire:model="task"></div>
<div><button wire:click="addTask">Add Task</button></div>
</div>
</cfoutput>install commandbox-cbwirecbwire create Counter
// Created /wires/Counter.cfc
// Created /views/wires/counter.cfm
// Created /tests/specs/integration/wires/CounterTest.cfccbwire create name=Counter views=false
// Created /wires/Counter.cfc
// Created /tests/specs/integration/wires/CounterTest.cfcfunction someAction() {
emit( "taskAdded" );
}function someAction() {
emit( "taskAdded", [
"some task",
now()
] );
}<button wire:click="$emit( 'taskAdded' )"><script>
cbwire.emit( 'taskAdded' );
</script>component extends="cbwire.models.Component"{
listeners = {
"taskAdded": "clearCache"
};
function clearCache(){}
}<script>
cbwire.on( 'taskAdded', task => {
console.log( 'A task was added. ');
})
</script>component extends="cbwire.models.Component" {
data = {
"photo": "",
"error": ""
};
function save() {
// 'photo' is now an instance of FileUpload@cbwire
if ( data.photo.getSize() > "100000" ) {
data.error = "Photo upload too big!";
} else {
// Store our file locally
fileWrite( expandPath( "./somewhere.jpg" ), data.photo.get() );
// Delete our file from CBWIRE's temporary storage and reset 'photo' data property
data.photo.destroy();
}
}
}<form wire:submit.prevent="save">
File: <input type="file" wire:model="photo">
<div><button type="submit">Save</button></div>
<!--- Show thumbnail --->
<cfif isObject( args.photo ) and args.photo.isImage()>
<div><img src="#args.photo.getPreviewURL()#"></div>
</cfif>
<cfif len( args.error ) >
<div class="error">#args.error#</div>
</cfif>
</form>Create dynamic properties for your UI Wires.
Define reactive properties for your UI Wires with just a few lines of code.
component extends="cbwire.models.Component"{
data = {
"task": ""
};
}component extends="cbwire.models.Component"{
property name="taskService" inject="TaskService@myapp";
// Data properties
data = {
"task": ""
};
// Action
function addTask(){
taskService.create( data.task );
}
}component extends="cbwire.models.Component"{
property name="taskService" inject="TaskService@myapp";
// Data properties
data = {
"task": ""
};
// Action
function addTask(){
taskService.create( this.getTask() );
}
}Create dynamic properties for your UI Wires.
Beautifully integrate your client-side JavaScript and CBWIRE using AlpineJS.
<head>
<script src="//unpkg.com/alpinejs" defer></script>
<!-- The "defer" attribute is important to ensure Alpine waits for CBWIRE to load first. -->
</head><div>
<div x-data="{ open: false }">
<button @click="open = true">Show More...</button>
<ul x-show="open" @click.away="open = false">
<li><button wire:click="archive">Archive</button></li>
<li><button wire:click="delete">Delete</button></li>
</ul>
</div>
</div>// wires/Counter.cfc
component extends="cbwire.models.Component" {
data = {
"counter": 0
};
function increment() {
data.counter += 1;
}
}Everything that has a beginning has an end. - The Oracle, Matrix
Help website users during wait times using Loading States.
You can use CBWIRE alongside ContentBox to build modernize, reactive applications with a powerful CMS included.
wire:target.<input type="file" wire:model="photo">
<div wire:loading wire:target="photo">Uploading...</div><script>
document.addEventListener("DOMContentLoaded", () => {
cbwire.hook('component.initialized', (wire) => {})
cbwire.hook('element.initialized', (el, wire) => {})
cbwire.hook('element.updating', (fromEl, toEl, wire) => {})
cbwire.hook('element.updated', (el, wire) => {})
cbwire.hook('element.removed', (el, wire) => {})
cbwire.hook('message.sent', (message, wire) => {})
cbwire.hook('message.failed', (message, wire) => {})
cbwire.hook('message.received', (message, wire) => {})
cbwire.hook('message.processed', (message, wire) => {})
});
</script><script>
document.addEventListener("livewire:load", function() {
var thisWire = cbwire.find('#args._id#'); // args._id contains the id of our wire
var count = thisWire.count; // gets the value of a data property called 'count'
thisWire.count = 5; // updates the values of a data property
thisWire.increment(); // calls the increment action on our wire
thisWire.addTask( 'someTask' ); // calls the addTask action and passes parameters
thisWire.call( 'increment' ); // same as increment call above
// On someEvent, console log
thisWire.on( 'someEvent', function() {
console.log('Got someEvent');
} );
thisWire.emit('someEvent', 'foo', 'bar'); // emits someEvent and pass parameters
} );
</script>component extends="cbwire.models.Component" {
property name="taskService" inject="taskService@myapp";
// Computed Properties
computed = {
"allTasks": function() {
return taskService.getAll();
}
};
}
component extends="cbwire.models.Component" {
property name="taskService" inject="taskService@myapp";
// Computed Properties
computed = {
"allTasks": function() {
return taskService.getAll();
}
};
// Action
function deleteTasks() {
// Notice below we don't invoke the method using computed.allTasks().
// We instead just use 'computed.allTasks'.
// At this point, cbwire has rendered our computed properties
// and overwritten the references with their result.
if ( arrayLen( computed.allTasks ) {
taskService.deleteAll();
}
}
}component extends="cbwire.models.Component" {
property name="taskService" inject="taskService@myapp";
// Computed Properties
computed = {
"allTasks": function() {
return taskService.getAll();
}
};
// Action
function deleteTasks() {
if ( arrayLen( this.getAllTasks() ) {
taskService.deleteAll();
}
}
}<cfoutput>
<div>
<ul>
<cfloop array="#args.allTasks#" index="task">
<li>#task#</li>
</cfloop>
</ul>
</div>
</cfoutput><cfoutput>
<div>
<h1>Task</h1>
<div>#args.task#</div>
</div>
</cfoutput>component extends="cbwire.models.Component"{
// Data properties
data = {
"task": "Some task here"
};
// Action
function resetForm() {
data.task = "Another value";
reset( "task" ); // Reverts data.task to 'Some task here'
}
}function someAction() {
reset( "task" ); // resets 'task' data property
reset( [ "task", "anotherprop" ] ); // reset multiple properties at once
reset(); // resets all properties
}component extends="cbwire.models.Component" {
property name="taskService" inject="taskService@myapp";
// Computed Properties
computed = {
"allTasks": function() {
return taskService.getAll();
}
};
}
component extends="cbwire.models.Component" {
// Computed Properties
computed = {
"allTasks": function() {
// return something here
}
};
// Action
function deleteTasks() {
if ( arrayLen( computed.allTasks() ) {
taskService.deleteAll();
}
}
}<cfoutput>
<div>
<ul>
<cfloop array="#args.computed.allTasks()#" index="task">
<li>#task#</li>
</cfloop>
</ul>
</div>
</cfoutput><!--- views/wires/counter.cfm --->
<cfoutput>
<div x-data="{ counter: #entangle( 'counter' )# }">
<div>CBWIRE value: #args.counter#</div>
<div>AlpineJS value: <span x-html="counter"></span></div>
<button
wire:click="increment"
type="button">Increment with CBWIRE</button>
<button
@click="counter += 1"
type="button">Increment with AlpineJS</button>
</div>
</cfoutput><div x-data="{ counter: #entangle( 'counter' )# }"><button wire:click="increment" type="button">Increment with CBWIRE</button>
<button @click="counter += 1" type="button">Increment with AlpineJS</button><div x-data="{ counter: #entangle( 'counter' )#.defer }">component extends="cbwire.models.Component"{
function addTask(){
sleep( 5000 ); // Optimize this code yo!
}
}<div>
<button wire:click="addTask">Add Task</button>
<div wire:loading>
Adding Task...
</div>
</div><div>
<button wire:click="addTask" wire:loading.attr="disabled">
Add Task
</button>
</div><div>
<button wire:click="addTask">Add Task</button>
<div wire:loading wire:target="addTask">
Adding task...
</div>
</div><div wire:loading.delay>...</div><div wire:loading.delay.shortest>...</div> <!-- 50ms -->
<div wire:loading.delay.shorter>...</div> <!-- 100ms -->
<div wire:loading.delay.short>...</div> <!-- 150ms -->
<div wire:loading.delay>...</div> <!-- 200ms -->
<div wire:loading.delay.long>...</div> <!-- 300ms -->
<div wire:loading.delay.longer>...</div> <!-- 500ms -->
<div wire:loading.delay.longest>...</div> <!-- 1000ms --><div wire:loading.flex>...</div>
<div wire:loading.grid>...</div>
<div wire:loading.inline>...</div>
<div wire:loading.table>...</div><div>
<button wire:click="addTask">Add Task</button>
<div wire:loading.remove>
Click 'Add Task'
</div>
</div>box install cbwire@be<!--- modules_app/contentbox-custom/_themes/cbwireTheme/layouts/blog.cfm --->
<cfoutput>
<!--- Global Layout Arguments --->
<cfparam name="args.print" default="false">
<cfparam name="args.sidebar" default="true">
<!DOCTYPE html>
<html lang="en">
<head>
<!--- Page Includes --->
#cb.quickView( "_blogIncludes" )#
<!--- ContentBoxEvent --->
#cb.event( "cbui_beforeHeadEnd" )#
<!--- PULL IN CBWIRE STYLING --->
#wireStyles()#
</head>
<body>
<!--- ContentBoxEvent --->
#cb.event( "cbui_afterBodyStart" )#
<!--- Header --->
#cb.quickView( '_header' )#
<!--- ContentBoxEvent --->
#cb.event( "cbui_beforeContent" )#
<!--- Main View --->
#cb.mainView( args=args )#
<!--- INCLUDE REACTIVE NEWSLETTER SIGNUP COMPONENT --->
#wire( "NewsletterSignup", {
validate: true
} )#
<!--- ContentBoxEvent --->
#cb.event( "cbui_afterContent" )#
#cb.quickView( view='_footer' )#
<!--- ContentBoxEvent --->
#cb.event( "cbui_beforeBodyEnd" )#
<!--- PULL IN CBWIRE JAVASCRIPT ASSETS --->
#wireScripts()#
</body>
</html>
</cfoutput><!--- modules_app/contentbox-custom/_themes/cbwireTheme/views/index.cfm --->
<div class="row">
<div class="col-12">
#wire( "ContactForm" )#
</div>
</div>component extends="cbwire.models.Component" {
data = {
"taskId": 0
};
function onMount( event, rc, prc, parameters ){
data.taskId = event.getValue( "taskId" );
}
}
component extends="cbwire.models.Component" {
data = {
"hydrated": false
};
function clicked() {}
function onHydrate( data ) {
// Note that computed properties are not rendered yet
data.hydrated = true;
}
function onRender( args ) {
return "
<div>
<div>Hydrated: #args.hydrated#</div>
<button wire:click='clicked'>Click me</button>
</div>
";
}
}component extends="cbwire.models.Component" {
data = {
"count": 1
};
function onHydrateCount( data ) {
// Note that computed properties are not rendered yet
data.count += 1;
}
}component extends="cbwire.models.Component" {
data = {
"rendered": true
};
computed = {
"currentDate": function() {
return now();
}
}
function onRender( args ) {
return "
<div>
<div>Rendered: #args.rendered# at #args.currentDate#</div>
</div>
";
}
}The magic sauce. Actions allow you to easily listen to page interactions and call a method on your Wires.


component extends="cbwire.model.Component"{
// Actions
function addTask(){
queryExecute( ... );
}
}<!--- Template --->
<div>
<button wire:click="addTask">Add Task</button>
</div><a href="" wire:click.prevent="doSomething">Do Something</a>
<button wire:click="doSomething">Do Something</button>
<input wire:keydown.enter="doSomething">
<form wire:submit.prevent="save">
<button>Save</button>
</form><button wire:foo="someAction"><button wire:click="addTask('Some Task')">Add Task</button>// Action
function addTask( taskName ){
} data = {
"task": ""
};
// Actions
function clearTasks(){
data.task = "";
} // Computed Properties
computed = {
"tasks": function() {
return queryExecute( "
select *
from tasks
" );
}
};
// Actions
function deleteTasks(){
if ( computed.tasks.recordCount ) {
// query to delete the tasks...
}
}<div>
#args.message#
<button wire:click="setMessageToHello">Say Hi</button>
</div><div>
#args.message#
<button wire:click="$set( 'message', 'Hello' )">Say Hi</button>
</div>function someAction() {
emit( "some-event" );
}component {
listeners = {
"some-event": "$refresh"
};
}CBWIRE's powerful directives allow you to listen for client side events, invoke actions, bind to data properties, and more.
Poll for state changes based on a specified interval without page refreshes. Hot dog!
You can listen for livewire:load and place any JavaScript there.
<div wire:poll></div><div>
<!--- Your component's template --->
<script>
document.addEventListener('livewire:load', function () {
// Your JS here.
})
</script>
</div>Similar to ColdBox, you can relocate users using relocate.
component extends="cbwire.models.Component"{
// Action
function clickButton() {
// Relocate to Google
relocate( url="https://www.google.com" );
// Relocate using URI
relocate( uri="/some/relative/path" );
// Relocate using event and set variables in Flash Ram
relocate( event="example.index", persistStruct={
success: true
} );
}
}<form wire:submit.prevent="someAction">
<button type="submit">Submit Form</button>
</form><input wire:keydown="foo" type="text"><input wire:keydown.enter="foo" type="text"><select wire:foo="bar"></select><input wire:model="foo" type="text"><input wire:model.debounce.1s="foo" type="text">
<input wire:model.debounce.500ms="foo" type="text"><input wire:model.defer="foo" type="text"><input wire:model.lazy="foo" type="text"><div wire:poll></div>
<div wire:poll.5s></div>
<div wire:poll.5000ms></div>
<div wire:poll.5s="fooMethod"></div><div wire:init="foo"></div><span wire:loading><img src="spinner.gif"></span><div wire:loading.class="highlight"></div><div wire:loading.class.remove="highlight" class="highlight"></div><button wire:loading.attr="disabled">...</button><div wire:dirty="foo">...</div><div wire:dirty.class="highlight">...</div><div wire:dirty.class.remove="highlight" class="highlight">...</div><button wire:dirty.attr="disabled">...</div><button wire:dirty.attr="disabled" wire:target="foo">...</div><div wire:ignore></div><div wire:ignore.self></div><a href="" wire:click.prevent="someAction">Click here</a><input wire:keydown.page-down="foo"><div>
<span wire:dirty wire:target="foo">Updating...</span>
<input wire:model.lazy="foo">
</div><div>
<label wire:dirty.class="text-red-500" wire:target="foo">Full Name</label>
<input wire:model.lazy="foo">
</div><div wire:poll.5s> <!-- poll every 5 seconds --> </div><div wire:poll="refreshTasks"></div>component extends="cbwire.models.Component" {
function refreshTasks() {}
}<cfif args.shouldPoll>
<div wire:poll="refreshTasks"></div>
<cfelse>
<div><!-- No more polling --></div>
</cfif>/**
* Relocate user browser requests to other events, URLs, or URIs.
*
* @event The name of the event to relocate to, if not passed, then it will use the default event found in your configuration file.
* @queryString The query string or a struct to append, if needed. If in SES mode it will be translated to convention name value pairs
* @addToken Wether to add the tokens or not to the relocation. Default is false
* @persist What request collection keys to persist in flash RAM automatically for you
* @persistStruct A structure of key-value pairs to persist in flash RAM automatically for you
* @ssl Whether to relocate in SSL or not. You need to explicitly say TRUE or FALSE if going out from SSL. If none passed, we look at the even's SES base URL (if in SES mode)
* @baseURL Use this baseURL instead of the index.cfm that is used by default. You can use this for SSL or any full base url you would like to use. Ex: https://mysite.com/index.cfm
* @postProcessExempt Do not fire the postProcess interceptors, by default it does
* @URL The full URL you would like to relocate to instead of an event: ex: URL='http://www.google.com'
* @URI The relative URI you would like to relocate to instead of an event: ex: URI='/mypath/awesome/here'
*
* @return void
*/
function relocate(
event = "",
queryString = "",
boolean addToken = false,
persist = "",
struct persistStruct = structNew()
boolean ssl,
baseURL = "",
boolean postProcessExempt = false,
URL,
URI
)Remove full-page reloads from your applications and create single-page applications with ease using Turbo.
// File: ./config/ColdBox.cfc
component{
function configure() {
moduleSettings = {
"cbwire" = {
"enableTurbo": true
}
};
}
}
npm i @hotwired/turboimport * as Turbo from "@hotwired/turbo"<script type="module">
import hotwiredTurbo from 'https://cdn.skypack.dev/@hotwired/turbo';
</script> #wireScripts()#
<script src="https://cdn.jsdelivr.net/gh/livewire/turbolinks@v0.1.x/dist/livewire-turbolinks.js" data-turbolinks-eval="false" data-turbo-eval="false"></script>
</body>.turbo-progress-bar {
height: 5px;
background-color: green;
}<!-- ./layouts/Main.cfm -->
<cfoutput>
<html>
<head>
<title>Turbo Page</title>
#wireStyles()#
</head>
<body>
<div class="turbo-progress-bar"></div>
<div class="mainContent">
Some content here
</div>
#wireScripts()#
</body>
</html>
</cfoutput><a href="/" data-turbo-preload>Home</a>Front-end testing of your UI Wires using a beautiful test API.
component extends="cbwire.models.BaseWireTest" {
function run(){
describe( "TaskList.cfc", function(){
it( "calling 'clearTasks' removes the tasks", function() {
wire( "TaskList" )
// Sets our data properties
.data( "tasks", [ "task1" ] )
// Verifies output in our template rendering
.see( "<li>task 1</li>" )
// Runs the 'clearTasks' action
.call( "clearTasks" )
// Verifies updated template rendering
.dontSee( "<li>task 1</li>" );
} );
} );
}
}wire( "TaskList" )
.data( "tasks", [ "task1", "task2" ] ) // one property at a time
.data( { "tasks" : [ "task1", "task2" ] } ); // struct of propertieswire( "TaskList" )
.computed( "count", function() { return 3; } ) // one property at a time
.computed( { "count" : function() { return 3; } } ); // struct of propertieswire( "TaskList" ).toggle( "showModal" );wire( "TaskList" ).call( "clearTasks" );
wire( "TaskList" ).call( "clearTasks", [ param1, param2 ] );wire( "TaskList" ).emit( "addedTask" );
wire( "TaskList" ).emit( "addedTask", [ param1, param2 ] );wire( "TaskList" ).see( "<h1>My Tasks</h1>" );wire( "TaskList" ).dontSee( "<h1>Someone Else's Tasks</h1> ");wire( "TaskList" ).seeData( "tasksRemoved", true );wire( "TaskList" ).dontSeeData( "tasksRemoved", true );