Lit-element: Add this.$ to LitElement as it's still very light-weight but usefule

Created on 9 Jun 2018  路  8Comments  路  Source: Polymer/lit-element

Polymer has this.$ as a convenient way to access all shadow root elements with an id defined, by id.
This can be easily added to LitElement as:

constructor() {
    super(...arguments);
    this.__renderComplete = null;
    this.__resolveRenderComplete = null;
    this.__isInvalid = false;
    this.__isChanging = false;

    // Add support for this.$
    this.$ = {};
}

ready() {
    this._root = this._createRoot();
    super.ready();

    // Add support for this.$
    for( const el of this._root.querySelectorAll( "*[id]" ) )
        this.$[el.id] = el;

    this._firstRendered();
}

and then accessed the same way as in Polymer: this.$.name.value for example, if we have an <input id="name"/>

Most helpful comment

I would be against this feature request. Since lit-element uses lit-html to handle elements declaratively, it's almost unnecessary to adjust elements manually, and if you still need it, you can do it by built-in tools like querySelector or getElementById called from this.shadowRoot.

All 8 comments

I would be against this feature request. Since lit-element uses lit-html to handle elements declaratively, it's almost unnecessary to adjust elements manually, and if you still need it, you can do it by built-in tools like querySelector or getElementById called from this.shadowRoot.

true, but in every project so far, I've written a helper method which translates this.q (for queryselector) to this.shadowRoot.querySelector

So what's the 'correct' way to validate a form with several fields while maintaining each field's value to property updates so that I can enable/disable the Submit button as the user changes values?
I can't see how I can access all input values without addressing them by ID and for that it's convenient to use this.$ not to change the value but to access/read it.

@pitus theoretically you could change a property of the element and use it to determine what to do (this.isSubmitButtonEnabled: boolean = false for example). However, I completely see your point and don't want to do it how I described either. Looks too complicated, too much like react ;)

Frankly, I don't know why we couldn't implement some kind of a two-way binding mixin for LitElements so that we could use it where it makes sense and without writing so much extra code for simple custom elements :( I'll end up writing my own set of helpers just to simplify element/form creation but I'd like to see how to do this better using universal, optional mixins is someone has experience preparing an example?

I think @lodin summarizes it nicely in https://github.com/Polymer/lit-element/issues/89#issuecomment-395972781 If you would like this behavior, you are of course free to define your own mixin or base class. Such features are more opinionated and would therefore not fit lit-element.

For posterity, and anyone landing here from google (greetings!), I present a simple mixin:

const isFunction = fn => typeof fn === 'function';

export default superclass => class $Element extends superclass {
  $(selector) {
    return (this.shadowRoot && isFunction(this.shadowRoot.querySelector))
      ? this.shadowRoot.querySelector(selector)
      : undefined;
  }
};

I can't see how I can access all input values without addressing them by ID and for that it's convenient to use this.$ not to change the value but to access/read it.

FWIW, you don't have to use IDs. This can be done pretty easily by using form.elements, which gives you all elements in the form that are mapped by their name attributes, which can be looped over, etc.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

erikkroes picture erikkroes  路  3Comments

aadamsx picture aadamsx  路  3Comments

quentin29200 picture quentin29200  路  3Comments

kurukururuu picture kurukururuu  路  3Comments

PotterDai picture PotterDai  路  4Comments