Lit-element: How to pass Objects as properties

Created on 21 May 2018  路  12Comments  路  Source: Polymer/lit-element

I am following a controller as attribute pattern (coming from Angular world):

const DEFAULT_TEXT = 'This is the default Text';
export class ButtonController {
    constructor(public text, 
                public color, 
                public onClick: () => void) {

    }
    public reset() {
        this.text = DEFAULT_TEXT;
    }
}
export class ButtonComponent extends LitElement {
    static get properties() {
        return {
            ctrl: ButtonController
        };
    }
}
customElements.define('bk-button', ButtonComponent);

Any ideas on how can I pass an instance of ButtonController to <bk-button ctrl=btnCtrl></bk-button>.

Most helpful comment

You should pass it down as a property like so:

<list-items .todoList=${this.todoList}></list-items>

You can see a similar example here.

All 12 comments

I suppose, you have to do it from parent component:

class Parent extends LitElement {
    // ...create your instance somewhere and write it to, e.g., "buttonController" property.

  _render () {
    return html`<bk-button ctrl=${this.buttonController}>Click me</bk-button>`
  }
}

Properties can be any javascript variable, so indeed you could pass along a controller instance from up top.

You'll find that with web components, it's much easier to use events and properties instead of a controller. So your button element could fire a click event, the parent component can catch it and modify the properties on the button (text, color etc.) as needed.

@LarsDenBakker Properties can only by native JS type. They are stringified by the browser when passing into the WebComponent.

@ashubham That's how attributes work, properties are regular js properties. When using lit-element, saying <foo-element foo=${myObject}> will under the hood do fooElement.foo = myObject in JS.

Saying <foo-element foo$=${myObject}> tells lit to set an attribute instead of a property, making it do fooElement.setAttribute('foo', myObject) under the hood.

@LarsDenBakker Makes sense, Thanks!

So, using
<foo-element foo=${myObject}>
will not cause any serialization / deserialization ?

No the property is just set in js

That's really good. However with this approach, I think that I'll always use this way for setting properties of my custom element inside lit-html, which will make my web component to be able to work only with lit-html, am I right?

say my component, given an array of products, displays the list of products in a table. I can now call it like <list-products p=${products}>

That's cool but how people without lit-html use that?

If your component is built with lit-html/lit-element then it will always be able to accept data in this way. When implemented it will be a requirement of the containing application to deliver this sort of data as properties. https://custom-elements-everywhere.com/ is a great tool for seeing what libraries and frameworks do that well and which accept native custom events for passing data up.

I've been trying to supply an object to a custom LitElement with no success :(
When I use <my-custom user=${this.Users}></my-custom> where this.User = {name: 'Piotr'} I end up with a string "${Users}" as a value for my-custom's user: Object property.
Does anyone have an example of a LitElement-based component showing a property of a supplied object and how that object has been passed along to that LitElement ?

Well, my bad ... I was using it on the top-level page so the browser, not LitElement was supplying my user attribute and it only understands strings. Once I moved the test into a test LitElement module, it's working as expected ;)

I am pretty new to this, I am having similar issue. Basically trying to pass an array from parent LitElement component to a child component and it showing me [Object object]

From Parent Element:
<list-items todoList=${this.todoList}></list-items>

Child Element :

import {LitElement,html} from '@polymer/lit-element';
import {repeat} from 'lit-html/directives/repeat.js';


class ListItems extends LitElement{
  static get properties(){
    return{
      todoList:Array
    }
  }
  constructor(){
    super();
    console.dir(this)
  }

  render(){
    console.log(this.todoList)
    return html`
      <ul>
      ${repeat(this.todoList,(todo)=>html`<li>${todo.item}</li>`)}
      </ul>
    `;
  }
}

customElements.define('list-items',ListItems);

You should pass it down as a property like so:

<list-items .todoList=${this.todoList}></list-items>

You can see a similar example here.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

aadamsx picture aadamsx  路  3Comments

quentin29200 picture quentin29200  路  3Comments

chrismbeckett picture chrismbeckett  路  3Comments

erikkroes picture erikkroes  路  3Comments

minht11 picture minht11  路  4Comments