0

My custom element is called "mb-bubbles". It represent a list of things. Each of these things must have at least the attributes "id" (Number) and "text" (String). If the component have the attribute "editable", you should be able to remove items ("blubbles") from it.

Its source code is:

import { LitElement, html, css } from '../vendor/lit-2.4.0/lit-all.min.js';

export class MbBlubbles extends LitElement {
    static styles = [
        css`
            :host {
                display: block;
                overflow: hidden;
            }
            
            .bubble {
                font-size: 14px;
                line-height: 14px;
                padding: 5px 10px;
                border-radius: 18px;
                background: #fff;
                display: block;
                float: left;
                margin: 4px 2px;
                cursor: pointer;
            }
            
            .bubble:hover {
                background: #def;
            }
            
            .bubble>.remove {
                display: inline-block;
                line-height: 20px;
                width: 20px;
                border-radius: 10px;
                text-align: center;
                font-weight: bold;
            }
            
            .bubble>.remove:hover {
                background: #fff;
            }
        `
    ];

    static get properties() {
        return {
            items: { type: Array }, // An array of objects with 2 attributes: "id" (Number) and "text" (String).
            editable: { type: Boolean }
        };
    }

    selectItem(item) {
        this.dispatchEvent(new CustomEvent('select-item', { detail: { item } }));
    }

    removeItem(item) {
        this.items = this.items.filter(it => it.id != item.id);
    }

    render() {
        return this.items.map(item => html`
            <div class="bubble" @click="${() => this.selectItem(item)}">
                ${item.text}
                ${this.editable ? html`<span class="remove" @click="${() => this.removeItem(item)}">&times;</span>` : ''}
            </div>
        `);
    }
}
customElements.define('mb-blubbles', MbBlubbles);

This component is used from outside in this way:

<mb-blubbles .items="${this.items}" editable></mb-blubbles>
${JSON.stringify(this.items)}

As you can see the property this.items seems unmodified.

How to modify the property from inside my custom component and have its changes reflected from the outside?

Is there any directive for that?

Pedro Urday
  • 93
  • 2
  • 5

1 Answers1

0

The reactive property only works within the component class, that is, updating this.items from within <mb-blubbles> will cause the contents of it to re-render, but it won't cause the parent to re-render, because the reactivity is based on the accessor of the component class itself.

If you need this to be updated in the parent, it would be better for the removeItems() method to dispatch an event, just like you're doing with the selectItem, and have the parent listen for that and update its own this.items.


class MbBlubbles extends LitElement {
  ...

  removeItem(item) {
    this.dispatchEvent(new CustomEvent('remove-item', { detail: { item } }));
  }

  ...
}


class ParentElement extends LitElement {
  static properties = { items: { type: Array } };

  removeItem(event) {
    const { item } = event.detail;
    this.items = this.items.filter(it => it.id != item.id);
  }

  render() {
    return html`
      <mb-blubbles @remove-item=${this.removeItem} .items=${this.items} editable></mb-blubbles>
      ${JSON.stringify(this.items)}
    `;
  }
}

Here's a working playground: https://lit.dev/playground/#gist=f61456f62076b849c0af02b2b1c7aff6

Augustine Kim
  • 841
  • 1
  • 5