view
Provides a view to render directly within the component’s element. The view is rendered with the component’s ViewModel instance.
String
A string that will be passed to can-stache to create a view. For example:
import {Component} from "can";
Component.extend( {
tag: "hello-world",
view: `Hello World!`
} );
document.body.innerHTML = `<hello-world></hello-world>`;
view(data, helpers, nodeList)
A view returned by can-stache. For example:
import {Component,stache} from "can";
Component.extend( {
tag: "hello-world",
view: stache(`Hello World!`)
} );
document.body.innerHTML = `<hello-world></hello-world>`;
Use
<content/>
elements within the view are replaced by the source elements within the component’s tag.
Background
Currently, most views are can-stache views. Please read stache's documentation to understand how to do things like:
- Write values to the page
- Branching logic
- Looping
This page details the special abilities of a Component's view that are not normally available to a generic stache view.
Use
The view specified by the view
property works similar to
the W3C Shadow DOM proposal. It represents the contents
of a custom element, while being able to reposition the user provided <can-template>
elements with <can-slot> elements.
NOTE:
Component
is also able to reposition with the <content> tag which is no longer favored by the W3C.
There are three things to understand about a component’s view:
- Rendered with a ViewModel - The view is rendered with
this
as the component instance’s ViewModel. - View Insertion - The rendered result of the view is inserted into the component’s element.
- <can-slot> elements - Any <can-slot> elements within the view act as insertion points for <can-template> elements.
Rendered with a ViewModel instance
The view
is rendered with this
as the component instance's ViewModel. For example,
the following prints the age
property of the ViewModel instance:
import {Component} from "can";
Component.extend({
tag: "my-component",
view: `You are {{this.age}}`,
ViewModel: {
age: {
default: 36
}
}
});
document.body.innerHTML = "<my-component></my-component>";
Notice that the view is rendered with an instance of the ViewModel, not the ViewModel constructor function. A new ViewModel instance is created for each element. For example, the following shows independent age values:
import {Component} from "can";
Component.extend({
tag: "my-component",
view: `You are {{this.age}}`,
ViewModel: {
age: {
value( {resolve} ){
const timer = setInterval( () => {
resolve( Math.round(Math.random() * 100) )
}, 1000);
return clearInterval.bind(window, timer);
}
}
}
});
document.body.innerHTML = `<my-component></my-component>.
<my-component></my-component>.
<my-component></my-component>.`;
View insertion
The view specified by view
is rendered directly within the custom tag.
For example the following component:
Component.extend( {
tag: "my-greeting",
view: "<h1>Hello There</h1>"
} );
With the following source html:
<header>
<my-greeting></my-greeting>
</header>
Produces the following html:
<header>
<my-greeting><h1>Hello There</h1></my-greeting>
</header>
If there is existing content within the source html, like:
<header>
<my-greeting>DO REMOVE ME!!!</my-greeting>
</header>
…that content is removed and replaced by the component’s view:
<header>
<my-greeting><h1>Hello There</h1></my-greeting>
</header>
Use <can-slot>
to position content within the source html.
<can-slot> elements
<can-slot> element inserts the content of <can-template> elements passed to the component. This makes customizing the HTML of a component much easier.
For example, the following defines a modal component whose content can be customized with
<can-template>
and positioned with <can-slot>
. Change the text of the input to see it
in action.
<my-app></my-app>
<style>
my-modal {
position: fixed;
top: 0px;
left: 0px;
right: 0px;
bottom: 0px;
z-index: 100;
}
.background {
width: 100%;
height: 100%;
background-color: #aCCaef;
opacity: 0.2;
}
.modal-container {
left: 50%;
top: 50%;
width: 300px;
height: 300px;
margin-top: -150px;
margin-left: -150px;
position: absolute;
border: 1px solid #e1e1e8;
background-color: white;
}
my-modal h3{
border-bottom: 1px solid #e1e1e8;
padding-left: 20px;
padding-bottom: 5px;
}
my-modal .modal-contents {
padding-left: 20px;
}
</style>
<script type="modal">
import {Component} from "can";
Component.extend({
tag: "my-modal",
view: `
<div class='background'></div>
<div class='modal-container'>
<h3>{{this.title}}</h3>
<div class='modal-contents'>
<can-slot name="contents"/>
</div>
</div>
`
});
Component.extend({
tag: "my-app",
view: `
{{# if(this.promptSave) }}
<my-modal title:raw="Wanna Save?">
<can-template name="contents">
<p> Save? </p>
<p>
<button class='btn btn-primary'
on:click="this.save()">Yes</button>
<button class='btn btn-warning'
on:click="this.cancel()">No</button>
</p>
</can-template>
</my-modal>
{{/ if }}
<div>
Meetup Name:
<input value:bind="value" disabled:from="this.saving"/>
{{# if(this.saving) }} <span class='info'>Saving ...</span> {{/ if }}
</div>
`,
ViewModel: {
value: "any",
backup: "any",
saving: "boolean",
get promptSave(){
return !this.saving &&
this.backup !== this.value;
},
save(){
var self = this;
this.saving = true;
setTimeout(() => {
this.set({
saving: false,
backup: this.value
});
},1000);
},
cancel(){
this.saving = false;
this.value = this.backup;
},
connectedCallback(){
this.backup = this.value;
}
}
});
</script>
Read <can-slot>'s documentation for more information.
Importing Views
The Setting Up CanJS guide has details on how to import stache views directly. For example,
the following example uses import view from "./app.stache";
:
import { Component } from "can";
import view from "./app.stache";
Component.extend({
tag: "my-app",
view,
ViewModel: {
message: {
default: "Hello World"
}
}
});
This allows:
- authoring stache files in their own files
- faster load times as the stache files are pre-parsed
Omitting the view
If the view is omitted, the content between the component tags (user DOM) is rendered
with the ViewModel
. The following renders Hi there!
between the <no-view>
and </no-view>
tags:
<my-app></my-app>
<script type="module">
import { Component } from "can";
Component.extend({
tag: "no-view",
ViewModel: {
message: {default: "Hi there!"}
}
});
Component.extend({
tag: "my-app",
view: `
<no-view>
{{this.message}}
</no-view>
`
})
</script>