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. 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.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.