1

I'm learning Lit and I want to make some common functionality that can be added either when extending the element or when using html`` to make a TemplateResult.

Example

For example, I have a custom input element which I want to be able to optionally apply a value converter on change.

I've made a simple mixin for this:

/**
 * Mixin to to enable value formatting
 * On focus, changes shadow dom input value to the elements value
 * On blur, changes shadow dom input value to formatted value
 */
export function ValueFormatterMixin(superClass) {
  return class extends superClass {
    static properties = {
      valueFormatter: { type: Function },
    };

    firstUpdated(changedProperties) {
      super.firstUpdated(changedProperties);
      this.addEventListener('focus', this.unmaskValue);
      this.addEventListener('blur', this.maskValue);
    }

    maskValue = (evt) => {
      if (typeof this.valueFormatter === 'function') {
        this.inputElement.value = this.valueFormatter(this.inputElement.value);
      }
    };

    unmaskValue = (evt) => {
      this.inputElement.value = this.value;
    };
  };
}

This lets me apply this when extending my base custom element:

// Focus: show raw entered number
// Blur: show formatted currency value 
class CurrencyElement extends ValueFormatterMixin(BasicInput) {
  valueFormatter(value) {
    return new Intl.NumberFormat('en-US', { style: 'currency' }).format(value);
  }
}

The Problem

I've realized I would also like to optionally add a valueFormatter when creating through element through HTML and not creating a custom element for the input field:

return html`
  <basic-input ${addValueFormatter((value) => `${value * 100}%`)}>
`;

I do not however want to add the ValueFormatterMixin to the basic-input class. I would like to keep that class as simple as possible, then lazily add on features. Most of the time I will not value formatter on my inputs so I don't want to include that functionally by default.

I do not believe its possible to retroactively add a mixin from a directive though. Is there a way to retroactively upgrade an element to include more functionality without defining a new component?

Joe Jankowiak
  • 1,059
  • 12
  • 37
  • **Note** ... Functions of the pattern `function MyMixin(superClass) { return class extends superClass { /* custom class implementation */ }; }` where the return value is an ad-hoc created anonymous class (which then mostly is used for sub-typing of another class) are factory functions. There is nothing involved in terms of mixin and/or composition. Everything from its implementation to its usage is dedicated to pure inheritance. – Peter Seliger Oct 20 '22 at 14:51
  • Could the OP come up with a more detailed explanation of the OP's code reuse scenario maybe accompanied by [a boiled down very specific code example](https://stackoverflow.com/help/minimal-reproducible-example) ideally as executable [stack snippet](https://meta.stackoverflow.com/questions/358992/ive-been-told-to-create-a-runnable-example-with-stack-snippets-how-do-i-do)? – Peter Seliger Oct 20 '22 at 14:58

0 Answers0