diff --git a/docs/can-stache-element.md b/docs/can-stache-element.md index 8708bca..0efbcc6 100644 --- a/docs/can-stache-element.md +++ b/docs/can-stache-element.md @@ -28,16 +28,16 @@ @@ -97,10 +97,10 @@ To create a [can-stache] view for the element, add a [can-stache-element/static. @@ -121,13 +121,13 @@ To add property definitions, add a [can-stache-element/static.props static props @@ -144,16 +144,16 @@ Methods (as well as getters and setters) can be added to the class body as well: @@ -172,40 +172,342 @@ If needed, [can-stache-element/lifecycle-hooks.connected] and [can-stache-elemen import { StacheElement } from "can/everything"; class Timer extends StacheElement { - static view = ` -

{{this.time}}

- `; - static props = { - time: { type: Number, default: 0 }, - timerId: Number - }; - connected() { - this.timerId = setInterval(() => { - this.time++; - }, 1000); - console.log("connected"); - } - disconnected() { - clearInterval(this.timerId); - console.log("disconnected"); - } + static view = ` +

{{ this.time }}

+ `; + static props = { + time: { type: Number, default: 0 }, + timerId: Number + }; + connected() { + this.timerId = setInterval(() => { + this.time++; + }, 1000); + console.log("connected"); + } + disconnected() { + clearInterval(this.timerId); + console.log("disconnected"); + } } customElements.define("time-er", Timer); let timer; document.body.querySelector("button#add").addEventListener("click", () => { - timer = document.createElement("time-er"); - document.body.appendChild(timer); + timer = document.createElement("time-er"); + document.body.appendChild(timer); }); document.body.querySelector("button#remove").addEventListener("click", () => { - document.body.removeChild(timer); + document.body.removeChild(timer); }); ``` @codepen @highlight 14-23,only +### Passing templates (customizing layout) + +It's a very common need to customize the html of a custom element. For example, +you might want a `` element to write out the "Hello World" message inside an +`

`, `

` or any other DOM structure. + +On a high level, this customization involves two steps: + +- Passing templates with `` +- Calling the templates with `{{ this.template() }}` + +#### Passing templates with `` + +When rendering a StacheElement in a [can-stache] template, you can declaratively create and +pass templates with the `` element. + +For example, one might want to customize one `` element to write out +"Hello World" message in a `

` or in an italic paragraph as follows: + +```html + + +

{{ message }}

+
+
+ + + +

I say "{{ message }}"!

+
+
+``` + +Here's what you need to know about ``: + +- Every `` __MUST__ have a name attribute. This is + the name of the property on the custom + element that will be set to the template. In the previous example, both ``'s will be created + with a `messageTemplate` property: + + ```js + document.querySelector("hello-world").messageTemplate //-> templateFunction() + ``` + +- You can have multiple ``s within a custom element. For example, + the following passes two templates to configure ``: + + ```html + + + {{ greeting }} + + + {{ subject }} + + + ``` + +- ``s have the same scope of the custom element, __plus__ + a `LetScope` that the custom element can optionally provide. This means + that a `{{ this.someData }}` immediately outside the `` will + reference the same value as `{{ this.someData }}` within a ``: + + ```html + {{ this.someData }} + + +

{{ message }}

+

Also: {{ this.someData }}

+
+
+ ``` + @highlight 1,5 + + The custom element can add additional data, like `message`, to these + templates. We will see how to do that in the next section. + +#### Calling the templates with `{{ this.template() }}` + +Once templates are passed to a custom element, you can call those templates +within the `StacheElement`'s [can-stache-element/static.view]. For example, +`` might call a passed `messageTemplate` as follows: + +```html + + + +``` +@codepen +@highlight 19,23,only + +While the above will render the passed `messageTemplate`, it will not provide it +a `{{ message }}` variable that can be read. You can pass values into a template +with a [can-stache/expressions/hash]. The following passes the message: + +```html + + + +``` +@codepen +@highlight 8,only + +Sometimes, instead of passing each variable, you might want to pass the +entire custom element: + +```html + + + +``` +@codepen +@highlight 8,21,only + +Finally, you might want to provide a default template if one is not +provided. You can do this either in the view or as a default props +value. + +In the view: + +```html + + + +``` +@codepen +@highlight 7-13,15,only + +As a default props value: + +```html + + + +``` +@codepen +@highlight 7-9,13,only + +If a property changes, the rendered passed template also update +its HTML like following: + +```html + + + +``` +@codepen +@highlight 17-19,28,only + + ## Testing Custom elements have [lifecycle methods](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements#Using_the_lifecycle_callbacks) that are automatically called by the browser. @@ -235,20 +537,20 @@ To test an element's properties and methods, call the [can-stache-element/lifecy ```js import { StacheElement } from "can/everything"; class Counter extends StacheElement { - static view = ` - Count: {{this.count}} - - `; - static props = { - count: 6 - }; - increment() { - this.count++; - } + static view = ` + Count: {{ this.count }} + + `; + static props = { + count: 6 + }; + increment() { + this.count++; + } } customElements.define("count-er", Counter); const counter = new Counter() - .initialize({ count: 20 }); + .initialize({ count: 20 }); counter.count === 20; // -> true @@ -265,20 +567,20 @@ To test an element's view, call the [can-stache-element/lifecycle-methods.render ```js import { StacheElement } from "can/everything"; class Counter extends StacheElement { - static view = ` - Count: {{this.count}} - - `; - static props = { - count: 6 - }; - increment() { - this.count++; - } + static view = ` + Count: {{ this.count }} + + `; + static props = { + count: 6 + }; + increment() { + this.count++; + } } customElements.define("count-er", Counter); const counter = new Counter() - .render({ count: 20 }); + .render({ count: 20 }); counter.firstElementChild.innerHTML === "20"; // -> true @@ -296,26 +598,26 @@ To test the functionality of the `connected` or `disconnected` hooks, you can ca import { StacheElement } from "can/everything"; class Timer extends StacheElement { - static view = ` -

{{this.time}}

- `; - static props = { - time: { type: Number, default: 0 }, - timerId: Number - }; - connected() { - this.timerId = setInterval(() => { - this.time++; - }, 1000); - } - disconnected() { - clearInterval(this.timerId); - } + static view = ` +

{{ this.time }}

+ `; + static props = { + time: { type: Number, default: 0 }, + timerId: Number + }; + connected() { + this.timerId = setInterval(() => { + this.time++; + }, 1000); + } + disconnected() { + clearInterval(this.timerId); + } } customElements.define("time-er", Timer); const timer = new Timer() - .connect(); + .connect(); timer.firstElementChild; // ->

0