DoneJS StealJS jQuery++ FuncUnit DocumentJS
5.33.3
6.0.0 4.3.0 3.14.1 2.3.35
  • About
  • Guides
  • API Docs
  • Community
  • Contributing
  • Bitovi
    • Bitovi.com
    • Blog
    • Design
    • Development
    • Training
    • Open Source
    • About
    • Contact Us
  • About
  • Guides
  • API Docs
    • Observables
      • can-bind
      • can-compute
      • can-debug
      • can-define
      • can-define/list/list
      • can-define/map/map
      • can-define-backup
      • can-define-stream
      • can-define-stream-kefir
      • can-event-queue
      • can-kefir
      • can-list
      • can-map
      • can-map-compat
      • can-map-define
      • can-observable-array
      • can-observable-object
      • can-observation
      • can-observation-recorder
      • can-observe
      • can-simple-map
      • can-simple-observable
      • can-stream
      • can-stream-kefir
      • can-value
    • Views
      • can-attribute-observable
      • can-component
      • can-stache
        • Tags
          • {{expression}}
          • {{{expression}}}
          • {{#expression}}
          • {{/expression}}
          • {{else}}
          • {{<partialName}}
          • {{!expression}}
          • {{-expression-}}
        • Helpers
          • and
          • console
          • debugger
          • domData
          • eq
          • for(of)
          • portal
          • if
          • joinBase
          • let
          • not
          • or
          • switch
          • case
          • default
        • Expressions
          • Bracket Expression
          • Call Expression
          • Hash Expression
          • KeyLookup Expression
          • Literal Expression
        • Methods
          • addBindings
          • addConverter
          • addHelper
          • addLiveHelper
          • from
          • safeString
        • Key Operators
          • ~compute
          • ./current
          • ../parent
          • scope
          • scope/key
          • this
          • key
        • Pages
          • Expressions
          • Helpers
        • Types
          • getterSetter
          • helper
          • helperOptions
          • sectionRenderer
          • simpleHelper
          • view
        • Deprecated
          • Helper Expression
          • scope.vars
          • {{data name}}
          • {{#each(expression)}}
          • {{#is(expressions)}}
          • {{#unless(expression)}}
          • {{#with(expression)}}
          • registerConverter
          • registerHelper
          • registerPartial
          • Legacy Scope Behavior
          • {{^expression}}
          • {{>key}}
      • can-stache-bindings
      • can-stache-converters
      • can-stache-element
      • can-stache-route-helpers
      • can-view-autorender
      • can-view-callbacks
      • can-view-import
      • can-view-live
      • can-view-model
      • can-view-nodelist
      • can-view-parser
      • can-view-scope
      • can-view-target
      • steal-stache
    • Data Modeling
      • can-connect
      • can-connect-feathers
      • can-connect-ndjson
      • can-connect-tag
      • can-fixture
      • can-fixture-socket
      • can-local-store
      • can-memory-store
      • can-ndjson-stream
      • can-query-logic
      • can-realtime-rest-model
      • can-rest-model
      • can-set-legacy
      • can-super-model
    • Routing
      • can-deparam
      • can-param
      • can-route
      • can-route-hash
      • can-route-mock
      • can-route-pushstate
    • JS Utilities
      • can-assign
      • can-define-lazy-value
      • can-diff
      • can-globals
      • can-join-uris
      • can-key
      • can-key-tree
      • can-make-map
      • can-parse-uri
      • can-queues
      • can-string
      • can-string-to-any
      • can-zone-storage
    • DOM Utilities
      • can-ajax
      • can-attribute-encoder
      • can-child-nodes
      • can-control
      • can-dom-data
      • can-dom-events
      • can-dom-mutate
      • can-event-dom-enter
      • can-event-dom-radiochange
      • can-fragment
    • Data Validation
      • can-define-validate-validatejs
      • can-type
      • can-validate
      • can-validate-interface
      • can-validate-legacy
      • can-validate-validatejs
    • Typed Data
      • can-cid
      • can-construct
      • can-construct-super
      • can-data-types
      • can-namespace
      • can-reflect
      • can-reflect-dependencies
      • can-reflect-promise
      • can-types
    • Polyfills
      • can-symbol
      • can-vdom
    • Core
    • Infrastructure
      • can-global
      • can-test-helpers
    • Ecosystem
    • Legacy
  • Community
  • Contributing
  • GitHub
  • Twitter
  • Chat
  • Forum
  • News
Bitovi

{{<partialName}}

  • Edit on GitHub

Create an inline named partial within the current template.

{{<partialName}}BLOCK{{/partialName}}

Creates a reusable sub-template from BLOCK named partialName that can be rendered with {{ partialName() }}. The following creates an addressView partial and renders it with two addresses:

import {stache} from "can";

const view = stache(`
  {{<addressView}}
      <address>{{this.street}}, {{this.city}}</address>
  {{/addressView}}

  <article>
      {{addressView(this.address1)}}
      {{addressView(this.address2)}}
  </article>
`)

const fragment = view({
  address1: {street: "Bitovi Way", city: "World" },
  address2: {street: "Stave", city: "Chicago" }
});

console.log(fragment.firstChild.innerHTML)
//-> <address>...</address><address>...</address>
document.body.appendChild(fragment);

Parameters

  1. partialName {String}:

    The name of the partial.

  2. BLOCK {sectionRenderer(context, helpers)}:

    a template to be captured and rendered later.

Use

Named partials are sub-templates in a larger template that aren’t rendered until called. They can be called any number of times with different contexts.

<partial-demo></partial-demo>

<script type="module">
import {Component} from "can";

Component.extend({
    tag: "partial-demo",
    view: `
        {{<addressView}}
            <div>{{this.street}}, {{this.city}}</div>
        {{/addressView}}

        <div>
            {{ addressView(this.business.address) }}
        </div>
        <ul>
            {{# for(person of this.people) }}
                <li>
                    {{ person.fullName }}, {{ person.birthday }}
                    {{ addressView(person.address) }}
                </li>
            {{/ for }}
        </ul>
    `,
    ViewModel: {
        business: {
            default(){
                return {
                    name: "Bitvoi",
                    address: { street: "Bitovi Way", city: "World" }
                };
            }
        },
        people: {
            default(){
                return [
                    {
                        fullName: "James Atherton",
                        address: {
                            street: "123 45th Street",
                            city: "Moline"
                        }
                    },
                    {
                        fullName: "Someone Else",
                        address: {
                            street: "678 90th St",
                            city: "Chicago"
                        }
                    }
                ];
            }
        }
    }
});
</script>

Named partials can also references their own name in a partial tag, which creates recursion.

<partial-demo></partial-demo>

<script type="module">
import {Component} from "can";

Component.extend({
    tag: "partial-demo",
    view: `
        {{< recursiveView }}
            <div>{{this.name}} <b>Type:</b> {{#if(this.nodes.length)}}Branch{{else}}Leaf{{/if}}</div>
            {{# for(node of this.nodes) }}
                {{ recursiveView(node) }}
            {{/ for }}
        {{/ recursiveView }}

        {{ recursiveView(this.yayRecursion) }}
    `,
    ViewModel: {
        yayRecursion: {
            default(){
                return {
                    name: "Root",
                    nodes: [
                        {
                            name: "Leaf #1 in Root",
                            nodes: []
                        },
                        {
                            name: "Branch under Root",
                            nodes: [
                                {
                                    name: "Leaf in Branch",
                                    nodes: []
                                }
                            ]
                        },
                        {
                            name: "Leaf #2 in Root",
                            nodes: []
                        }
                    ]
                }
            }
        }
    }
});
</script>

Would result in:

<div>Root <b>Type:</b> Branch</div>
<div>Leaf #1 in Root <b>Type:</b> Leaf</div>
<div>Branch under Root <b>Type:</b> Branch</div>
<div>Leaf in Branch <b>Type:</b> Leaf</div>
<div>Leaf #2 in Root <b>Type:</b> Leaf</div>

Too Much Recursion

When working with recursive named partials, be aware that by default, expressions will walk up the context chain if the property is not found in the current context.

So if your data and template looks like this:

Given this data:

{
    yayRecursion: {
        name: "Root",
        nodes: [
            {
                name: "Branch #1 in Root",
                nodes: [
                    {
                        name: "Problem Child",
                        nodes: undefined
                    }
                ]
            }
        ]
    }
}

This template:

{{<recursive}}
    <div>{{name}} <b>Type:</b> {{#if(nodes.length)}}Branch{{else}}Leaf{{/if}}</div>
    {{#each(nodes)}}
        {{>recursive}}
    {{/each}}
{{/recursive}}

{{>recursive yayRecursion}}

Will recurse on nodes and your output will be something like this:

<div>Root <b>Type:</b> Branch</div>
<div>Branch #1 in Root <b>Type:</b> Leaf</div>
<div>Problem Child <b>Type:</b> Branch</div>
<div>Problem Child <b>Type:</b> Branch</div>
<div>Problem Child <b>Type:</b> Branch</div>
<div>Problem Child <b>Type:</b> Branch</div>
...
<div>Problem Child <b>Type:</b> Branch</div>
(hangs from too much recursion)

This is because when it’s rendering that named partial with “Problem Child” as the context, the template sees nodes here: {{#each(nodes)}}, then it checks the current context (Problem Child), doesn’t find anything called nodes, then moves up the scope to its parent context to check for nodes. Since nodes is on the parent (and contains the Problem Child), it uses that for the #each() and you’re stuck in infinite recursion.

To avoid that, it’s best practice to always be specific about the context for your expressions within a named partial:

{{<recursive}}
    <div>{{./name}} <b>Type:</b> {{#if(./nodes.length)}}Branch{{else}}Leaf{{/if}}</div>
    {{#each(./nodes)}}
        {{>recursive .}}
    {{/each}}
{{/recursive}}

{{>recursive yayRecursion}}

which prevents the default behavior for expressions to look up the context chain.

CanJS is part of DoneJS. Created and maintained by the core DoneJS team and Bitovi. Currently 5.33.3.

On this page

Get help

  • Chat with us
  • File an issue
  • Ask questions
  • Read latest news