5

Based on the selection of a radio button, I would like to toggle the read-only attribute of lightning-input element. setAttribute method on DOM element doesn't seem to work.

app.html

<template>
    <div class="slds-grid">
        <div class="slds-col">
            <lightning-radio-group name="opportunityCreation"
            label="Create an Opportunity"
            options={options}
            value={createOpp}
            onchange={createOppHandler}>
            </lightning-radio-group>
        </div>
        <div class="slds-col">
            <lightning-input label="Opportunity Name" data-id="oppName">

            </lightning-input>
        </div>
    </div>
</template>

app.js

import { LightningElement, track, api } from 'lwc';

export default class App extends LightningElement {

    @track options = [{'label': 'Yes', value:'yes'},{'label':'No', value:'no'}];
    @track createOpp = 'yes';
    createOppHandler(event){
        this.createOpp = event.detail.value;
        let inputTextElem = this.template.querySelector("[data-id='oppName']");
        if(this.createOpp === 'no'){
            inputTextElem.setAttribute("read-only", "");
        }
        else{
            inputTextElem.removeAttribute("read-only");
        }
    }
}

Playground link

2 Answers 2

6

The usual way to address this is to hold the "read-only-ness" as tracked state (a change to it causes refresh of the UI) and to then conditionally render the input with or without the required read-only flag.

app.html

<template>
    <div class="slds-grid">
        <div class="slds-col">
            <lightning-radio-group name="opportunityCreation"
            label="Create an Opportunity"
            options={options}
            value={createOpp}
            onchange={createOppHandler}>
            </lightning-radio-group>
        </div>
        <div class="slds-col">
            <template if:false={readOnly}>
                <lightning-input label="Opportunity Name" data-id="oppName">
                </lightning-input>
            </template>
            <template if:true={readOnly}>
                <lightning-input label="Opportunity Name" data-id="oppName" read-only>
                </lightning-input>
            </template>
        </div>
    </div>
</template>

app.js

import { LightningElement, track, api } from 'lwc';

export default class App extends LightningElement {

    @track options = [{'label': 'Yes', value:'yes'},{'label':'No', value:'no'}];
    @track createOpp = 'yes';
    @track readOnly = false;

    createOppHandler(event) {
        this.createOpp = event.detail.value;
        this.readOnly = this.createOpp == "no";
    }
}

Also updated in your playground.

UPDATE:

I suspect the markup:

            <template if:false={readOnly}>
                <lightning-input label="Opportunity Name" data-id="oppName">
                </lightning-input>
            </template>
            <template if:true={readOnly}>
                <lightning-input label="Opportunity Name" data-id="oppName" read-only>
                </lightning-input>
            </template>

Can be replaced by:

            <lightning-input label="Opportunity Name" data-id="oppName" read-only={readOnly}>
            </lightning-input>

Though I haven't tested it. The technique I showed is, however, good for other cases where you want to pass different parameters rather than just different parameter values.

1
  • Yes, the replaced markup in the update definitely works and is more concise/DRY.
    – jbyrd
    Commented Feb 22, 2022 at 21:43
1

Alternatively, if you want to use the querySelector method, you could keep the html the same, but slightly modify how you're setting the attribute.

Original html:

<template>
    <div class="slds-grid">
        <div class="slds-col">
            <lightning-radio-group name="opportunityCreation"
                label="Create an Opportunity"
                options={options}
                value={createOpp}
                onchange={createOppHandler}>
            </lightning-radio-group>
        </div>
        <div class="slds-col">
            <lightning-input label="Opportunity Name" data-id="oppName">

            </lightning-input>
        </div>
    </div>
</template>

Modified js:

import { LightningElement, track, api } from 'lwc';

export default class App extends LightningElement {

    @track options = [{'label': 'Yes', value:'yes'},{'label':'No', value:'no'}];
    @track createOpp = 'yes';
    createOppHandler(event){
        this.createOpp = event.detail.value;
        let inputTextElem = this.template.querySelector("[data-id='oppName']");
        if(this.createOpp === 'no'){
            inputTextElem.readOnly = true;
        }
        else{
            inputTextElem.readOnly = false;
        }
    }
}

One thing to keep in mind is that some things (like checkboxes) don't seem to observe read-only attribute, so you'll need to use disabled attribute instead. But the assignment is still the same:

inputTextElem.disabled = true;

Ultimately though, unless you have a specific use case for using the querySelector, I think Phil W's solution works the best by tying the attribute to a js variable.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .