Resolution/Answer Below at bottom
Original Question
I have a LWC that end users use to complete a custom Search within Salesforce. We format the Search Bar to make reading the input clearer to the user. Unfortunately when users make a mistake in the middle of the search term and they click backspace or make an edit the cursor then jumps to the end of the search term. See the following Images:
Cursor is in the Middle ready to make an edit:
After edit is made (in this case - backspace) the cursor jumps to the End:
LWC - HTML:
<!-- Account Number Search -->
<div onkeyup={anKeyUp} class="slds-col">
<lightning-layout multiple-rows="false" vertical-align="end">
<lightning-layout-item flexibility="auto" padding="around-small">
<div class="slds-form-element">
<div class="slds-form-element__control">
<lightning-input type="search" label="Account Number" onchange={handleCardSearchTerm}
data-id="ANS" value={cardNumberFormating} max-length="19">
</lightning-input>
</div>
</div>
</lightning-layout-item>
<lightning-layout-item flexibility="auto" padding="around-small">
<lightning-button label="Search" variant="brand" onclick={handleCMSearch}>
</lightning-button>
</lightning-layout-item>
</lightning-layout>
</div>
LWC - JS:
handleCardSearchTerm(event) {
event.preventDefault();
console.log('Handling Search Term Update...');
this.cardSearchTerm = event.detail.value;
console.log('Search Term: ', event.detail.value);
this.reformat(event.detail.value);
}
// Reformating Functionality
reformat(value){
// Goal to reformat card search func to look like CC format xxxx-xxxx-xxxx-xxxx
console.log(value);
var v = value.replace(/\s+/g, '').replace(/[^0-9]/gi, '');
var matches = v.match(/\d{4,16}/g);
var match = matches && matches[0] || '';
var parts = [];
var i;
for (i=0; i<match.length; i+=4) {
parts.push(match.substring(i, i+4))
}
if(parts.length) {
this.cardNumberFormating = parts.join('-');
} else {
this.cardNumberFormating = value;
}
console.log('Formatted Card Number: ', this.cardNumberFormating);
}
Ideally after a user makes an update to the search term I would like the cursor to maintain its location rather than going to the end as it currently does.
Any suggestions on how this can be completed/Resolved?
ANSWER // RESOLUTION
So Salesforce/Lightning Web Components do not provide access to the selectionStart (or SelectionEnd) Property - at least not for <lightning-input>
. So in order to make the property accessible the <lightning-input>
had to be created via standard HTML. See Below:
<div class="slds-form-element">
<label class="slds-form-element__label" for="text-input-id-1">Account Number</label>
<div
class="slds-form-element__control slds-input-has-icon slds-input-has-icon_left">
<svg class="slds-icon slds-input__icon slds-input__icon_left slds-icon-text-default"
aria-hidden="true">
<use
xlink:href="/_slds/icons/utility-sprite/svg/symbols.svg?cache=9.37.1#search">
</use>
</svg>
<input type="text" id="form-element-01"
class="slds-input" maxlength="19" data-id="ANS"
onkeyup={formatSearchTerm}/>
</div>
</div>
Once this was done I was able to access the property and update it via JS as described by sfdcfox below. I did so with the following:
formatSearchTerm(event){
event.preventDefault();
console.log('Formatting Input');
this.cardSearchTerm = event.target.value;
console.log('Search Term: ', this.cardSearchTerm);
// Goal to reformat card search func to look like CC format xxxx-xxxx-xxxx-xxxx
let value = event.target.value;
let oldLength = value.length;
value = value.replace(/\D/g, "");
let selectionStart = event.target.selectionStart;
var v = value.replace(/\s+/g, '').replace(/[^0-9]/gi, '');
var matches = v.match(/\d{4,16}/g);
var match = matches && matches[0] || '';
var parts = [];
var i;
for (i=0; i<match.length; i+=4) {
parts.push(match.substring(i, i+4))
}
if(parts.length) {
value = parts.join('-');
} else {
value = value;
}
this.cardNumberFormating = value;
if (oldLength == selectionStart) {
selectionStart = value.length;
}
event.target.value = value;
event.target.selectionStart = selectionStart;
event.target.selectionEnd = selectionStart;
}
Side Note: In my original code I used the 'value' attribute in the lightning-input and tried in the new recreated input element. This was causing issues for me accounting for the cursor jumping - this had to be removed.
Salesforce why would you move to standard HTML/JS development (LWC) but not make certain properties accessible? Doesn't make sense... Not that I don't love that you made the move, I do.