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>.
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.
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.