0

I want to react on events started by elements placed in the data-grid rows. Vaading data-grid prevents events from bubbling up to the parent component containing the grid. Having buttons placed in the grid column rendered for each row I cannot catch the click or any other event from the component that hosts the grid.

The examples from https://vaadin.com/components/vaadin-grid/html-examples are relying on js hooks being attached in the html file. I am working with Lit-element and trying to do the same at firstUpdated() callback. The problem is that apparently at this point the table is not available.

<vaadin-grid id="test" .items=${this.data} theme="compact">
    <vaadin-grid-column width="40px" flex-grow="0">
        <template class="header">#</template>
        <template>
            <vaadin-button style="font-size:10px;" theme="icon" focus-target @click="${(e) => { console.log(e) }}">
                <iron-icon icon="icons:create"></iron-icon>
            </vaadin-button>
        </template>
    </vaadin-grid-column>
</vaadin-grid>

I expected to have the log and nothing happens as the grid component prevents event from bubbling up to my component.

The code that tries to implement renderer property for vaadin-grid-column:

import { LitElement, html, css } from 'lit-element'
import {render} from 'lit-html';

import '@vaadin/vaadin-grid/vaadin-grid.js'
import '@vaadin/vaadin-grid/vaadin-grid-filter-column.js'
import '@vaadin/vaadin-grid/vaadin-grid-sort-column.js';
import '@vaadin/vaadin-grid/vaadin-grid-filter.js';
import '@vaadin/vaadin-grid/vaadin-grid-sorter.js'

export default class MyClass extends LitElement {
    static get properties () {
        return {
            data: { 
                type: Array,
                hasChanged: () => true
            },

        }
    }

    get grid() {
        return this.shadowRoot.querySelector('vaadin-grid');
    }

    constructor () {
        super()
        this.data = []//is being assigned from super as a property to a custom element 
    }
    render () {
        return html`
            <vaadin-grid id="test" .items=${this.data}>
                <vaadin-grid-column .renderer=${this.columnRenderer} header="some header text"></vaadin-grid-column>
            </vaadin-grid>
        `
    }

    columnRenderer(root, column, rowData) {
        render(html`test string`, root);
    }
}
window.customElements.define('my-elem', MyClass)
  • Edited 1: Added the code using renderers. A new issue is the html blocks from renderer are being inserted as [object Object] in the datatable. Only the plain string gets populated as expected. – user3424586 Jul 11 '19 at 14:59
  • Update 1: I am able to render html elements assigning them to the root.innerHTML, the events are still not tracked though. As an alternative, I added the vaadin-grid-selection-column and use events from parent on selected items instead – user3424586 Jul 12 '19 at 13:44
  • Update 2 (final): the solution proposed by Alan is correct for my problem. The issue with lit-html rendering is related to the custom project setup I have and not the pwa starter kit that was used as a starting point. – user3424586 Jul 25 '19 at 14:04
  • I wonder if someone could update this to the more recent 'lit' - when I attempt to do so, I get some issues in my columnRenderer() - 1. render() seems to have moved (or perhaps it is one thing that hasn't moved and it's still imported from lit-html), 2. when I use the render imported from lit-html, it renders objects, so something has changed. – Max Waterman Jun 15 '21 at 06:20
  • ^ need to `import { render } from 'lit/html.js';` – Max Waterman Jun 16 '21 at 06:21

1 Answers1

0

When using vaadin-grid inside LitElement-based components you should use renderers

Here's how your code would look using renderers

import {LitElement, html} from 'lit-element';
// you need lit-html's render function
import {render} from 'lit-html';

class MyElement extends LitElement {
  // we'll just assume the data array is defined to keep the sample short
  render() {
    return html`
      <vaadin-grid id="test" .items=${this.data} theme="compact">
        <vaadin-grid-column width="40px" flex-grow="0" .renderer=${this.columnRenderer} .headerRenderer=${this.columnHeaderRenderer}></vaadin-grid-column>
      <vaadin-grid>
    `;
  }
  columnHeaderRenderer(root) {
    render(html`#`, root);
    // you could also just do this
    // root.textContent = '#'
    // or actually just use the column's header property would be easier tbh
  }
  columnRenderer(root, column, rowData) {
    render(
      html`
        <vaadin-button style="font-size: 10px;" theme="icon" focus-target @click="${(e) => { console.log(e) }}">
          <iron-icon icon="icons:create"></iron-icon>
        </vaadin-button>
      `, root);
  }
}

You can see this and more of vaadin-grid's features in action in LitElement in this Glitch created by one of the vaadin team members

Alan Dávalos
  • 2,568
  • 11
  • 19
  • Hi, thanks for the reply. The solution seems to almost get me there. I added the renderer and am able to render simple text assigning it to the root.textContent. However, when I am using render() the table renders [object Object] and not the HTML. After some investigation, the closest issue I could find was https://github.com/Polymer/lit-element/issues/390 with few ideas as of why this could happen. None of the solutions seems to work for me. Since we set the render results as properties on columns It seems logical to pass the object and not necessary the string. – user3424586 Jul 10 '19 at 15:06
  • P.s. porting the example into my project has the same result. [object] is populated instead of the html. apparently the issue is in the settings – user3424586 Jul 10 '19 at 15:18
  • Can you post an example of how you are trying to do the rendering for you app? – Alan Dávalos Jul 11 '19 at 03:19