Updating an Input's Value Without Losing Cursor Position

Updating an input's value without losing cursor position

$("#beLowerCase").on('input', function(){

// store current positions in variables
var start = this.selectionStart,
end = this.selectionEnd;

this.value = this.value.toLowerCase();

// restore from variables...
this.setSelectionRange(start, end);
});

(fiddle)


This actually works with CSS as well:

#beLowerCase{
text-transform:lowercase;
}

And server can take care of the actual lower-casing...

Angular - Updating an Input-Field without losing the cursor position

you need "play" with the properties selectionStart and selectionEnd of the own input, you can see an example in this SO (The question use a directive, it's only to help you to get the idea)

Simplifying so much, if you pass the own input (you can also use viewChild and ask about this.yourvariable.nativeElement)

<input #myinput type="text" class="form-control"
[value]="value | number: '.0' : 'en-US'"
(input)="onInput($event,myinput)">

Some like

onInput(event: Event,inputhtml:any): void {
//get the actual position of the cursor
let pos=inputhtml.selectionStart;

//get the characteres not digit before change:
const nondigits=...

//change the value
this.value = +(<HTMLInputElement>event.target).value.split(',').join('');

//recalcule the position, e.g.
pos+=nondigits;

//in a setTimeout (sometime this can be not neccesary)
setTimeout(()=>{
//use selectionStart and selectionEnd to position the cursor
inputhtml.selectionStart=inputhtml.selectionEnd=pos

})
}

How to maintain cursor position when updating input value

I think you should use a lexter/parser instead to convert bbcode to HTML (unless the reason is that you want to learn by doing).

Here's one that might work for you. It has support for the default bbcode blocks and makes it possible to define you own.

<head>
<!-- Optional styling for .xbbcode-* classes -->
<link rel="stylesheet" type="text/css" href="xbbcode.css">
</head>
<body>
<script src="xbbcode.js"></script>
<script>
var text = document.getElementById("comment").innerHTML;
var result = XBBCODE.process({
text: text,
removeMisalignedTags: false,
addInLineBreaks: false
});
console.error("Errors", result.error);
console.dir(result.errorQueue);
console.log(result.html); //=> <span class="xbbcode-b">Hello world</span>
</script>
</body>

update textarea value, but keep cursor position

Here is a pair of functions that get and set the selection/caret position in a text area in all major browsers.

Note: if you don't need to support IE <= 8, just use the selectionStart and selectionEnd properties (MDN). All of the complicated code below is just there to support old versions of IE.

function getInputSelection(el) {
var start = 0, end = 0, normalizedValue, range,
textInputRange, len, endRange;

if (typeof el.selectionStart == "number" && typeof el.selectionEnd == "number") {
start = el.selectionStart;
end = el.selectionEnd;
} else {
range = document.selection.createRange();

if (range && range.parentElement() == el) {
len = el.value.length;
normalizedValue = el.value.replace(/\r\n/g, "\n");

// Create a working TextRange that lives only in the input
textInputRange = el.createTextRange();
textInputRange.moveToBookmark(range.getBookmark());

// Check if the start and end of the selection are at the very end
// of the input, since moveStart/moveEnd doesn't return what we want
// in those cases
endRange = el.createTextRange();
endRange.collapse(false);

if (textInputRange.compareEndPoints("StartToEnd", endRange) > -1) {
start = end = len;
} else {
start = -textInputRange.moveStart("character", -len);
start += normalizedValue.slice(0, start).split("\n").length - 1;

if (textInputRange.compareEndPoints("EndToEnd", endRange) > -1) {
end = len;
} else {
end = -textInputRange.moveEnd("character", -len);
end += normalizedValue.slice(0, end).split("\n").length - 1;
}
}
}
}

return {
start: start,
end: end
};
}

function offsetToRangeCharacterMove(el, offset) {
return offset - (el.value.slice(0, offset).split("\r\n").length - 1);
}

function setInputSelection(el, startOffset, endOffset) {
if (typeof el.selectionStart == "number" && typeof el.selectionEnd == "number") {
el.selectionStart = startOffset;
el.selectionEnd = endOffset;
} else {
var range = el.createTextRange();
var startCharMove = offsetToRangeCharacterMove(el, startOffset);
range.collapse(true);
if (startOffset == endOffset) {
range.move("character", startCharMove);
} else {
range.moveEnd("character", offsetToRangeCharacterMove(el, endOffset));
range.moveStart("character", startCharMove);
}
range.select();
}
}

When you change the textarea's value, first save the selection, then restore it afterwards:

var t = document.getElementById("textarea");
var sel = getInputSelection(t);
t.value = some_new_value;
setInputSelection(t, sel.start, sel.end);

How to prevent the cursor from moving when modifying an input's value?

You can use the selectionStart property of the input fields to determine where the caret was before you completely rewrite the input field.

document.querySelector("#my-input").addEventListener("change", function() {
// Get the position of the caret before you rewrite the input field
let caretPosition = document.querySelector("#my-input").selectionStart;

// Rewrite the input field here

// Put the caret back to where it was
document.querySelector("#my-input").selectionStart = caretPosition;
});

Input cursor jumps to end of input field on input event

If you (or Vue) copy a new value into an input, the cursor will be set to the end of the input. If you want to retain the previous position, you will need to capture the position, make the change, then on the $nextTick restore the position.

Also note that if you are going to set this.input in the handler, there's no point in your using v-model, too. It's also unlikely that saving the event is sensible, but you can.

new Vue({  el: "#app",  data() {    return {      input: null,      event: null    }  },  methods: {    handleInput(e) {      const el = e.target;      const sel = el.selectionStart;      const upperValue = el.value.toUpperCase();
el.value = this.input = upperValue; this.event = e; this.$nextTick(() => { el.setSelectionRange(sel, sel); }); } }});
#app {  background: #fff;  border-radius: 4px;  padding: 20px;  transition: all 0.2s;}
input { margin-bottom: 20px;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script><div id="app">  <input type="text" @input="handleInput">  <p>{{ event ? event.target.value : null }}</p>  <p>    {{input}}  </p></div>


Related Topics



Leave a reply



Submit