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
        • define
          • extend
          • tag
          • view
          • ViewModel
        • create
          • <tag bindings...>
          • new Component
        • elements
          • <can-slot>
          • <can-template>
        • lifecycle hooks
          • connectedCallback
        • deprecated
          • beforeremove
          • <content>
          • events
          • helpers
          • leakScope
          • viewModel
      • can-stache
      • 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

new Component

  • Edit on GitHub

Programmatically instantiate a component

new Component([options])

Create an instance of a component without rendering it in a template. This is useful when you:

  • have complex logic for switching between different components (e.g. routing)
  • want to create components without adding them to the page (e.g. testing)

The following defines a MyGreeting component and creates a my-greeting element by calling new on the component’s constructor function:

const HelloWorld = Component.extend({
    tag: "hello-world",
    view: `
        <can-slot name="greetingTemplate" />
        <content>world</content>
        <ul>{{#each(items)}} {{this}} {{/each}}</ul>
    `,
    ViewModel: {
        items: {}
    }
});

// Create a new instance of our component
const componentInstance = new HelloWorld({

    // values with which to initialize the component’s view model
    viewModel: {
        items: ["eat"]
    },

    // can-stache template to replace any <content> elements in the component’s view
    content: "<em>{{message}}</em>",

    // <can-template> strings rendered by can-stache with the scope
    templates: {
        greetingTemplate: "{{greeting}}"
    },

    // scope with which to render the <content> and templates
    scope: {
        greeting: "Hello",
        message: "friend"
    }
});

myGreetingInstance.element; // is like <my-greeting>Hello <em>friend</em> <ul> <li>eat</li> </ul></my-greeting>

myGreetingInstance.viewModel; // is HelloWorld.ViewModel{items: ["eat"]}

Changing the component’s view model will cause its element and any bindings to be updated:

myGreetingInstance.viewModel.items.push("sleep");

myGreetingInstance.element; // is like <my-greeting>Hello <em>friend</em> <ul> <li>eat</li> <li>sleep</li> </ul></my-greeting>

See the Programmatically instantiating a component section for details.

Parameters

  1. options {Object}:

    Options for rendering the component, including:

    • content {String|Function}: Similar to the <content> tag, the LIGHT_DOM to be rendered between the component’s starting and ending tags; can either be a string (which will be parsed by can-stache by default) or a view function.
    • scope {Object}: An object that is the scope with which the content should be rendered.
    • templates {Object<String,String|Function>}: An object that has keys that are <can-template> names and values that are either plain strings (parsed by can-stache by default) or view functions.
    • viewModel {Object}: An object with values to bind to the component’s view model.

Use

You can instantiate new component instances programmatically by using the component’s constructor function. This is useful when you:

  • have complex logic for switching between different components (e.g. Routing)
  • want to create components without adding them to the page (e.g. Testing)

The following defines a MyGreeting component and creates a my-greeting element by calling new on the component’s constructor function:

import {Component} from "can";

const MyGreeting = Component.extend({
  tag: "my-greeting",
  view: "Hello {{subject}}",
  ViewModel: {
    subject: "string"
  }
});

const myGreetingInstance = new MyGreeting({
  viewModel: {
    subject: "friend"
  }
});

console.log( myGreetingInstance.element );
// logs <my-greeting>Hello friend</my-greeting>

console.log( myGreetingInstance.viewModel );
// logs MyGreeting.ViewModel{subject: "friend"}

In the example above, the viewModel is passed in as an option to the component’s constructor function.

In addition to viewModel, there are templates, scope, and content options. Read below for details on all the options.

viewModel

The viewModel option is used to create the component’s ViewModel instance and bind to it. For example:

import {Component, DefineMap, value} from "can";

const appVM = new DefineMap({
  association: "friend"
});

const MyGreeting = Component.extend({
  tag: "my-greeting",
  view: "{{greeting}} {{subject}}",
  ViewModel: {
    greeting: "string",
    subject: "string"
  }
});

const myGreetingInstance = new MyGreeting({
  viewModel: {
    greeting: "Hello",
    subject: value.bind(appVM, "association")
  }
});

console.log( myGreetingInstance.element );
// logs <my-greeting>Hello friend</my-greeting>

console.log( myGreetingInstance.viewModel );
// logs MyGreeting.ViewModel{subject: "friend"}

The way the component is instantiated above is similar to this example below, assuming it’s rendered by can-stache with appVM as the current scope:

<my-greeting greeting:raw="Hello" subject:bind="association"></my-greeting>

You can recreate one-way and two-way bindings with can-value, which has bind, from, and to methods for creating two-way, one-way parent-to-child, and one-way child-to-parent bindings, respectively.

const appVM = new DefineMap({
  family: {
    first: "Milo",
    last: "Flanders"
  }
});

const NameComponent = Component.extend({
  tag: "name-component",
  view: "{{fullName}}",
  ViewModel: {
    givenName: "string",
    familyName: "string",
    get fullName() {
      return this.givenName + " " + this.familyName;
    }
  }
});

const componentInstance = new NameComponent({
  viewModel: {
    // like givenName:from="family.first"
    givenName: value.from(appVM, "family.first"),
    // like familyName:bind="family.last"
    familyName: value.bind(appVM, "family.last"),
    // like fullName:to="family.full"
    fullName: value.to(appVM, "family.full"),
  }
});

The way the component is instantiated above is similar to this example below, assuming it’s rendered by can-stache with appVM as the current scope:

<my-greeting
  givenName:from="family.first"
  familyName:bind="family.last"
  fullName:to="family.full"
></my-greeting>

This will result in an appVM with the following data:

{
  family: {
    first: "Milo",
    full: "Milo Flanders",
    last: "Flanders"
  }
}

Changing the component’s view model will cause its element and any bindings to be updated:

componentInstance.viewModel.familyName = "Smith";

componentInstance.element; // is <name-component>Milo Smith</name-component>

appVM.family.last; // is "Smith"

templates

The templates option is used to pass a into a component when it is instantiated.

import {Component} from "can";

const TodosPage = Component.extend({
    tag: "todos-page",
    view: `<ul><can-slot name='itemList' /></ul>`
});

const todosPageInstance = new TodosPage({
    scope: {
        items: ["eat"]
    },
    templates: {
        itemList: `{{#for(item of items)}} <li>{{item}}</li> {{/for}}`
    }
});

document.body.appendChild(todosPageInstance.element);

This makes todosPageInstance.element a fragment with the following structure:

<todos-page>
  <ul>
    <li>eat</li>
  </ul>
</todos-page>

content

The content option is used to pass LIGHT_DOM into a component when it is instantiated, similar to the <content> tag.

import {Component} from "can";

const HelloWorld = Component.extend({
  tag: "hello-world",
  view: "Hello <content>world</content>"
});

const helloWorldInstance = new HelloWorld({
  content: "<em>mundo</em>"
});

document.body.appendChild(helloWorldInstance.element);

This makes helloWorldInstance.element an element with the following structure:

<hello-world>Hello <em>mundo</em></hello-world>

scope

You can also provide a scope with which the content should be rendered:

import {Component} from "can";

const HelloWorld = Component.extend({
  tag: "hello-world",
  view: "Hello <content>world</content>"
});

const helloWorldInstance = new HelloWorld({
  content: "<em>{{message}}</em>",
  scope: {
    message: "mundo"
  }
});

document.body.appendChild(helloWorldInstance.element);

This makes helloWorldInstance.element a fragment with the following structure:

<hello-world>Hello <em>mundo</em></hello-world>

initializeBindings

By default bindings are initialized when a component is created. For most components this is what you want. However if you are only conditionally inserting a component it can leak memory if bindings are setup. Setting initializeBindings: false prevents the setting up of bindings until the component is inserted into a view.

import {Component, stache} from "can";

const HelloWorld = Component.extend({
  tag: "hello-world",
  view: "Hello world"
});

const helloWorldInstance = new HelloWorld({
  initializeBindings: false
});

// Bindings are not setup.

const view = stache("{{component}}");
document.body.append(view({ component: helloWorldInstance }));

// Now they are!

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