Components
Components
Now that you've learned about observables, templates, and controls, it's time to learn about can.Component. can.Component makes it easy to combine the functionality of these features. We'll use it to rewrite the todo example.
Create a component constructor function by extend can.Component like:
Where:
Now let's dive into component's properties a bit more.
Tag
A component represents a custom html element whose nodeName is specified by the component's tag attribute. To create a can.Component constructor function that manages functionality on a
<todos-editor>
elements, extend can.Component like:Now, when a
<todos-editor>
element is found in a mustache template, an instance of the component is created on the element.This control doesn't do anything. Lets change that by filing out other properties.
Template
Lets put an
<input/>
element inside<todos-editor>
elements by adding a template property:This replaces any source content with the component's template. The result of rendering
template
looks like:Notice that "todos-editor element" is removed.
To render the source content within the template, add a
<content/>
tag like:This results in:
If no source content is provided between the custom tags, you can specify default content to use within the
<content></content>
tags like:If the source template is changed to:
This results in:
You can also specify the template as a can.view.renderer like:
By default the component's template renders with the same [can.view.Scope scope] as the scope where the custom element is found within the source template. But, you can adjust the scope with can.Component's scope property.
Scope
A template's scope property allows you to adjust the scope used to render the component's template. If a plain JavaScript object is used, that object is used to extend and create an instance of can.Map and add to the top to the scope used to render the template.
For example, we can add a visible property to control if the input element is visible or not:
Scope bindings
This isn't interesting without a way to change toggling the visible property. We can tell our template to call a
toggle
method on the scope anytime someone clicks the form with template bindings like:Check it out here:
When bindings are used like this, the scope function is called back with the element's context, the element, and the event.
Scope value functions
Scope functions can also be called for their value. For example:
Scope as a can.Map constructor function
The scope object can also be defined as a can.Map constructor function. This makes it easier to test the scope object independent of the component's rendering. For example:
Passing values to a component's scope
Often, you want to pass values to a component. This is done by setting attributes on the component's element. For example, we might want to pass a todo to the todo editor from the source template. To do this, add a
todo='mytodo'
attribute.Notice the
can-value
attribute on the input element. This sets up a two-way binding between the todo's name and the input element. This lets you change the todo's name.Sometimes, you want to specify attribute values that are not looked up in the scope. For example, you might want to give
todos-editor
placeholder text as follows:We can modify the component to read the string placeholder value by setting
placeholder
in the scope to "@". This is a special flag that indicates to simply use the attribute's value.If you remove the input's text, a placeholder will show up:
Helpers
The helpers object registers local helpers avaialble within the component. The following lists todo and adds a
todoClass
helper that is used to set the className on a todo's<li>
element:Notice that
options.context
is used to retrieve the todo becausethis
withintodoClass
is the scope.Events
A component's events object is used to create a [can.Control] that has access to scope as
this.scope
. Use it to listen to events safely.For example, we can create a
todos-app
component that manages the high-level state of the application. It listens to changes in can/route and updates the scope'stodo
property. And, if a todo is destroyed that matches the route'sid
, the route'sid
is removed:You can use templated event binding to listen to changes in scope objects. Adding the following to
todo-app
's events object listens to todo changes and saves the changes.Finally, to put this all together, we render a template like: