2

I would like to add and remove 'over' from my class on an element created using a lit-html template triggered by 'dragEnter' and 'dragLeave':

#app {
  background-color: #72a2bc;
  border: 8px dashed transparent;
  transition: background-color 0.2s, border-color 0.2s;
}

#app.over {
  background-color: #a2cee0;
  border-color: #72a2bc;
}
const filesTemplate = () =>
html`
  <button id="app"     
    @dragover=${??}
    @dragleave=${??}     
  >
    Click Me
  </button>
`;

In my old system I called these methods in a separate module via an event emitter, but I am hoping I can make it all defined in the template using lit-html.

 dragEnter(e) {
    this.view.element.className += ' over';
  }

  dragLeave(e) {
    this.view.element.className = element.className.replace(' over', '');
  }

3 Answers 3

2

It depends what your custom element looks like. With your template you could just put @dragover=${this.dragEnter}. However, if you want this to apply to your entire custom element and not just the button you can do something like this:

connectedCallback() {
super.connectedCallback();

this.addEventListener('dragover', this.dragEnter);

}

If you do not have custom element and just use lit-html by itself you have to put your event handlers dragEnter(e)and dragLeave(e) into the template like so: @dragover=${this.dragEnter}

You need to add the class with classList.add in dragEnter and remove it in dragLeave. In the future you maybe can use classMap directive in lit-html, however there is nothing wrong with just using classList. I would stick with just using classList. In a very distant future css might also have a selector for it: Is there a CSS ":drop-hover" pseudo-class?

6
  • I don't have any custom elements, I am using lit-html by itself, not with lit-element or some equivalent. I am not sure how your code relates to the CSS, are you saying I have to use a callback to this.dragEnter, if so, what would be in that method, how will it refer to the <button>? Cheers!
    – Sumomo
    Commented Jan 23, 2019 at 22:11
  • Updated the answer based on your comment. Commented Jan 24, 2019 at 6:32
  • Thanks for the update, but it is only a partial answer, you did not address the CSS or what the dragEnter() method might contain. I am new to lit-html and the docs are woefully inadequate right now (it is pre-release still). What is best practice? Should my methods mutate the DOM as before? Should I feed in new variables into the template/re-write it with new bindings for class? Run the render() function again after each callback? If you could provide a full solution in code would be great :) Thanks for your time, it is much appreciated!
    – Sumomo
    Commented Jan 24, 2019 at 9:30
  • Added some more clarification Commented Jan 24, 2019 at 19:25
  • Cheers! classMap was what I was looking for, seems made for the job :) Nothing in the docs, but the comments in the source code explain github.com/Polymer/lit-html/blob/master/src/directives/…
    – Sumomo
    Commented Jan 25, 2019 at 17:19
2

I think that, in order to solve the problem in a "lit-html style", the solution has to be something like this:

import { html, render} from 'lit-html';
import { classMap } from 'lit-html/directives/class-map.js';

const myBtnClasses = {
  over: false
};
function dragEnter(e) {
  myBtnClasses.over = true;
  renderFiles();
}
function dragLeave(e) {
  myBtnClasses.over = false;
  renderFiles();
}

const filesTemplate = (classes) =>
html`
  <button id="app" class="${classMap(myBtnClasses)}"
    @dragover=${dragEnter} @dragleave=${dragLeave}     
  >
    Click Me
  </button>
`;
function renderFiles() {
  render(filesTemplate(myBtnClasses), YOUR_CONTAINER);
}

When using lit-html you have to express your UI as a function of your "state" and "rerender" each time your state changes, so the best solution in this little example is to consider your classes as part of your state.

0

Anyway better than

this.view.element.className += ' over';

is

this.view.element.classList.add('over');

And instead

this.view.element.className = element.className.replace(' over', '');

use

this.view.element.classList.remove('over');

This is better because of allowing to avoid many bugs like adding the same class many times.

I do not know lit-html but try

let sayHello = (name, myClass) => html`<h1 class="${myClass}">Hello ${name}</h1>`;

https://lit-html.polymer-project.org/

1
  • Thanks for the great tip regarding classList, I copied from old code and ender up with cruft, well spotted! I am really looking for the syntax to set the event listeners to make these changes to the class within the lit-html template. Your example code would work in part, but misses the vital syntax to integrate with the event listening :(
    – Sumomo
    Commented Jan 23, 2019 at 17:40

Not the answer you're looking for? Browse other questions tagged or ask your own question.