8

During a submit I'd like to intercept the event and run some custom validation on the input values. Here is a simplified template of what I'd like to do:

<template>
  <lightning-input type="text" name="foo" label="Foo"></lightning-input>
  <lightning-button onclick={foo} label='Validate'></lightning-button>
</template>
foo() {
  let element = this.template.querySelector("lightning-input");
  let value = element.value;

  if (value !== '42') {
    element.setCustomValidity("Error!");
  } else {
    element.setCustomValidity("");
  }

  element.reportValidity();
}

The code above works as expected. But ideally I'd like to individually target a unique element. When I then read the documentation it clearly states:

Don’t use ID selectors with querySelector. The IDs that you define in HTML templates may be transformed into globally unique values when the template is rendered. If you use an ID selector in JavaScript, it won’t match the transformed ID.

With the attribute id out of the question, I thought that the attribute name could "replace" it. So I re-wrote the code to the following:

foo() {
  let element = this.template.querySelector("[name='foo']");
  let value = element.value;

  if (value !== '42') {
    element.setCustomValidity("Error!");
  } else {
    element.setCustomValidity("");
  }

  element.reportValidity();
}

But that does not work. No matter how I try to target an individual element with the name attribute, the query selector never finds it. Is this a bug or am I doing something wrong here?

Note: If I add the attribute data-id on it and query for that instead; it works.

3

the problem is that the name attribute is not placed on the lightning-input element but on the internal input element. So you are trying to access component internals which is prevented by Lockerservice as you are not the owner of the lightning namespace.

If you want to select the component element you have to use something like a data attribute like mentioned in your Note

1

LWC component authors control whether or not the attribute you set in your template "reflects", or "is rendered" in the DOM, but they must make an active decision to do so. Due to the power of defaults, aside from a small set of global HTML attributes which do reflect by default, it's most likely that the attribute you set in your template will not show up in the DOM. This is basically what's going on for the name attribute of lightning-input.

This default behavior may be inverted in the future so that what you see in your template more closely matches what you see in the DOM, but your best bet today is to rely on global HTML attributes that the component cannot easily prevent from reflecting, namely the class and data-* attributes.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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