can.Control
Create organized, memory-leak free, rapidly performing, stateful controls with declarative event binding. Use can.Control
to create UI
controls like tabs, grids, and context menus,
and organize them into higher-order business rules with
can.route. It can serve as both a traditional view and a traditional controller.
can.Control( [staticProperties,] instanceProperties )
Create a new, extended, control constructor function. This functionality is inherited from can.Construct and is deprecated in favor of using can.Control.extend.
Parameters
-
staticProperties
{Object}
OptionalAn object of properties and methods that are added the control constructor function directly. The most common property to add is defaults.
-
instanceProperties
{Object}
An object of properties and methods that belong to instances of the
can.Control
constructor function. These properties are added to the control'sprototype
object. Properties that look like event handlers (ex:"click"
or"li mouseenter"
) are setup as event handlers (see Listening to events).
Returns
{constructor(element, options) => can.Construct}
A control constructor function that has been
extended with the provided staticProperties
and instanceProperties
.
new can.Control( element, options )
Create an instance of a control. setup processes
the arguments and sets up event binding. Write your initialization
code in [can.Control.prototype.init]. Note, you never call new can.Control()
directly,
instead, you call it on constructor functions extended from can.Control
.
Parameters
-
element
{HTMLElement | NodeList | CSSSelectorString}
Specifies the element the control will be created on.
-
options
{Object}
OptionalOption values merged with can.Control.defaults and set as this.options.
Returns
{can.Control}
A new instance of the constructor function extending can.Control.
The Control Lifecycle
The following walks through a control's lifecycle with an example todo list widget. It's broken up into the following lifecycle events:
Extending a control
The following example builds up a basic todos widget for listing and completing todo items. Start by creating a control constructor function of your own by extending can.Control and defining an instance init method.
Creating a control instance
Create an instance of the Todos control on the
todos
element with:The control's associated EJS template looks like:
init(element, options)
[can.Control.prototype.init] is called with the below arguments when new instances of can.Control are created:
this.element
on the control instance.this.options
on the control instance. Note that static is used formally to indicate that default values are shared across control instances.Any additional arguments provided to the constructor will be passed as normal. Use can.view to produce a document fragment from your template and inject it in the passed element. Note that the
todos
parameter passed to can.view below is an instance of can.List:this.element
element is the NodeList consisting of the element the control is created on.
Each library wraps elements differently. If you are using jQuery, for example, the element is wrapped with
jQuery( element )
.this.options
options is the second argument passed to
new can.Control()
, merged with the control's static defaults property.Listening to events
Control automatically binds prototype methods that look like event handlers. Listen to __click__s on
<li>
elements like:When an
<li>
is clicked,"li click"
is called with:Control uses event delegation, so you can add
<li>
s without needing to rebind event handlers.To destroy a todo when its
<a href="javascript://" class="destroy">
link is clicked:When the todo is destroyed, EJS's live binding will remove its LI automatically.
Templated Event Handlers Part 1
"{eventName}"
Customize event handler behavior with
"{NAME}"
in the event handler name. The following allows customization of the event that destroys a todo:Values inside
{NAME}
are looked up on the control'sthis.options
first, and then thewindow
. For example, we could customize it instead like:The selector can also be templated.
Templated Event Handlers Part 2
"{objectName}"
Control can also bind to objects other than
this.element
with templated event handlers. This is critical for avoiding memory leaks that are so common among MVC applications.If the value inside
{NAME}
is an object, Control will bind to that object to listen for events. For example, the following tooltip listens to clicks on the window:This is convenient when listening for model changes. If EJS were not taking care of removing
<li>
s after their associated models were destroyed, we could implement it inTodos
like:on()
on rebinds a control's event handlers. This is useful when you want to listen to a specific model and change it:
Destroying a control
destroy unbinds a control's event handlers and releases its element, but does not remove the element from the page.
When a control's element is removed from the page destroy is called automatically.
All event handlers bound with Control are unbound when the control is destroyed (or its element is removed).
Brief aside on destroy and templated event binding. Taken together, templated event binding, and control's automatic clean-up make it almost impossible to write leaking applications. An application that uses only templated event handlers on controls within the body could free up all data by calling
$(document.body).empty()
.Tabs Example
Here is an example of how to build a simple tab widget using can.Control: