LWC Selectors and Element Identification

Introduction

We have querySelector and querySelectorAll in LWC for getting/selecting HTML elements. We can not use ID selectors because they get modified at runtime (when rendered).

Access Elements the Component Owns

To access elements rendered by a component, use the "template" property.

this.template.querySelector();
this.template.querySelectorAll();

Use these methods to look for the elements that your component rendered.

Some key points to keep in mind

  • The order of elements is not guaranteed.
  • Elements not rendered to the DOM aren't returned in the "querySelector" result.
  • Don't use ID selectors with "querySelector". The IDs that you define in HTML template 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.
<!-- example.html -->
<template>
   <div>First <slot name="task1">Task 1</slot></div>
   <div>Second <slot name="task2">Task 2</slot></div>
</template>
// example.js
import { LightningElement } from 'lwc';

export default class Example extends LightningElement {
    renderedCallback() {
        this.template.querySelector('div'); // <div>First</div>
        this.template.querySelector('span'); // null
        this.template.querySelectorAll('div'); // [<div>First</div>, <div>Second</div>]
    }
}

IMPORTANT: Don't use the "window" or "document" global properties to query for DOM elements. See DOM Access Containment. Also Salesforce don't recommend using javaScript to manipulate the DOM. It's better to use the Lightning Web Components HTML directives to write declarative code.

Now consider the below code:

<div class="first-class">
	<lightning-input class="second-class" ></lightning-input>
	<lightning-input class="second-class" ></lightning-input>
	<lightning-input class="second-class" ></lightning-input>
</div>
 

Now here what if you have to set the value of 3rd lightning-input dynamically? In Aura we provide a unique aura:id to the elements and use this aura:id attribute to set the value dynamically, but that is not possible here.

You can do it like this way:

let firstClass = this.template.querySelector(".first-class");
let secondClasses = firstClass.querySelectorAll(".second-class");
secondClasses[2].value = 'Some Value';

Well! we have achieved our target but code seems a little bit confusing, also there are too many lines. We are traversing the whole "first-class" div and and then it's "second-class" child elements. The question is can we optimize the above code and the answer is Yes we can!

 We can use custom attributes to uniquely identify and select an element we want. As shown below:

<div class="first-class">
	<lightning-input data-my-id="in1" class="second-class"></lightning-input>
	<lightning-input data-my-id="in2" class="second-class"></lightning-input>
	<lightning-input data-my-id="in3" class="second-class"></lightning-input>
</div>

Now to fetch or set the 3rd lightning-input value:

this.template.querySelector("lightning-input[data-my-id=in3]").value = "Some Value";

Using querySelectorAll

querySelectorAll returns a list representing a list of the template elements that match the specified group of selectors.

<!-- lwcinputs.html   -->
<template>
    <br>
    <div style="width:200px; padding-left:50px">
        <lightning-input class="inp" label="Enter Name" name="input1"></lightning-input>
        <lightning-input class="inp" label="Enter Age" name="input2"></lightning-input>
        <br>
        <center>
            <lightning-button label="Click" onclick={handleClick} variant="brand"></lightning-button>
        </center>
    </div>


    Hello {name}!   <br>
    Your age {age} 

There are 2 lightning-input and a button which calls handleClick.

import { LightningElement, track } from 'lwc';


export default class App extends LightningElement {
    @track name='Best in the World';
    @track age;


    handleClick(event)
    {
        console.log(event.target.label);
        var inp=this.template.querySelectorAll("lightning-input");


        inp.forEach(function(element){
            if(element.name=="input1")
                this.name=element.value;

            else if(element.name=="input2")
                this.age=element.value;
        },this);
    }} 

In handleClick function, querySelectorAll will return a list of lightning-input element. Next a forEach loop check each element name and assigns a appropriate value.

Instead of using tag name in "querySelectorAll", we can use css class name in querySelectorAll. for ex.:

<lightning-input class="inp" label="Enter Name" name="input1"></lightning-input> <lightning-input class="inp" label="Enter Age" name="input2"></lightning-input>

both elements have same class "inp".

var inp=this.template.querySelectorAll(".inp");

Rest of the code is same. 

Thanks for reading, Happy codding... 😊

1 Comments

Previous Post Next Post