0

I'm busy migrating a static js/html application to Lit. I'm finding the platform to be the most easy to migrate old static code to a framework.

However, I'm having some big issues where rendered code are modified externally. Let me explain:

  render() {

    return html`

    ${this.chartsData.map((chart) =>

        html`<div id="chart${row.id}">
          <div id="chart_content${row.id}">
          </div> 
        </div>
      
      )}`
}

Now, later on I add content to the "chart_content" divs which are generated from external classes from jquery or basic DOM etc. Very complex code which I cannot add in the render function. Basically I create the content as follows:

var lineChart = new LineChart(`chart_content_${chartId}`);

Porting this to Lit as a Lit-Element is not possible for me as libraries such as Plotly JS does not support Lit.

Lit rendering is basically used to create the "wireframe" content and the detail is added later on for now.

The problem is, when I delete a chart from chartsData such as:

this.chartsData = this.chartsData.filter(x=>x.id != id);

the code from chart_content are not deleted with the rest of the div. It gets pushed into existing chart divs which are not associated with the content. I expected that Lit would delete the chart_content div as well with the main chart container but it does not happen. This of course creates havoc. Honestly I'm not exactly sure what it does, but I'm 100% sure the content is not deleted.

I need a way to tell Lit to associate the sub-div with the main-div and also delete/move the content with the main div where required.

ceds
  • 2,097
  • 5
  • 32
  • 50

1 Answers1

1

You need to define your array as property.

function add() {
  const list = document.getElementById('list');
  list.addOne();
}

function rm() {
  const list = document.getElementById('list');
  list.removeOne();
}
<script type="module">
import {
  LitElement,
  css
} from "https://unpkg.com/lit-element/lit-element.js?module";
import {html, unsafeStatic} from "https://unpkg.com/lit/static-html.js?module";
import {repeat} from "https://unpkg.com/lit/directives/repeat.js?module";

class MyList extends LitElement {
  
  static get properties() {
    return {
      chartsData: {type: Array},
    };
  }
  
  constructor() {
    super();
    this.chartsData = [
      {id: 1, html: '<div style="background-color: blue">1</div>'},
      {id: 2, html: '<div style="background-color: red">2</div>'},
      {id: 3, html: '<div style="background-color: blue">3</div>'},
      {id: 4, html: '<div style="background-color: red">4</div>'},
      {id: 5, html: '<div style="background-color: blue">5</div>'},
      {id: 6, html: '<div style="background-color: red">6</div>'},
    ];
  }
  
  removeOne() {
    this.chartsData.pop();
    this.chartsData = [...this.chartsData];
  }
  
  addOne() {
    const id = this.chartsData.length + 1;
    const html = `<div style="background-color: ${id % 2 ? 'blue' : 'red'}">${id}</div>`;
    this.chartsData.push({id, html})
    this.chartsData = [...this.chartsData];
  }
  
  render() {
    return html`
      ${repeat(this.chartsData, (row, index) => html`<div id="chart${row.id}">
              <div id="chart_content${row.id}">${unsafeStatic(row.html)}</div> 
             </div>`
      )}`
  }
}

customElements.define("my-list", MyList);
</script>
<br/>
<button onclick="add()">Add</button>
<button onclick="rm()">Remove</button>
<br/>
<my-list id=list></my-list>
Christian
  • 3,503
  • 1
  • 26
  • 47
  • Thanks for the assistance. However, that's not exactly my issue. Not sure if you don't understand it. I have included all the arrays etc as properties. That's not the issue. Updates get triggered etc. My problem is the custom injected HTML after rendering which breaks future updates – ceds Mar 24 '22 at 10:17
  • No then I don't understand. Where does row come from? In your snippet at least a tick is missing. The chart in the map function is not used at all. Could you create a minimum reproducible example? And what is custom injected HTML? I also wouldn't see a problem wrapping plotly js into a web-component. Are you recreating the array on every change (I assume so by using filter)? – Christian Mar 24 '22 at 10:23
  • I will try to produce an example. Think that's the only way to do it. But the essence of the problem is me using jquery afterwards to inject code into divs that were created by Render. It seems like Lit does not like it as it throws the content around at random with new updates. – ceds Mar 24 '22 at 10:27
  • 1
    Then you are breaking a major rule. Only a state change should cause a change in the dom. It's all about state. Never manipulate the generated html only the state. – Christian Mar 24 '22 at 10:52
  • Yes I know that, but life is not perfect is it? I'm busy migrating an old html/jquery website step by step. I need to make it work somehow – ceds Mar 24 '22 at 11:19
  • Is there not a way to generate the html and add the html as a property which the template then renders? I tried this but it is injected as text, not html. Could not find a workaround for that – ceds Mar 24 '22 at 11:20
  • A library like Plotly also changes the DOM without changing the state. So does that mean you cannot use any external library like Plotly with Lit ? – ceds Mar 24 '22 at 11:21
  • I'm assuming some kind of "wrapper" is possible to encapsulate the old jquery/html code. Other libraries as well like Plotly. But I have no idea how to do that. My only idea is to get the html as a property but as said I cannot make it work – ceds Mar 24 '22 at 11:24
  • So the real question might be how to "wrap" old code, and not how to "hack" Lit to work with something it was not designed to work with – ceds Mar 24 '22 at 11:24
  • Normally it is not a problem to wrap other libs. Even if they change the html. But you are trying both, changing state and dom. – Christian Mar 24 '22 at 11:48
  • @ceds I updated my example to show you the usage of unsafeStatic (see different imports now). This way you can add arbitrary html code. But be careful. It's unsafe. ;) – Christian Mar 24 '22 at 12:01
  • 1
    I also updated to use repeat instead of map for better performance. – Christian Mar 24 '22 at 12:16
  • Repeat did the trick. I knew Lit had to be intelligent enough to handle something simple like this. Very happy about the results – ceds Mar 24 '22 at 19:23
  • Cool, glad to help out. – Christian Mar 24 '22 at 19:43