function insertText(elemID, text) {
var elem = document.getElementById(elemID);
elem.innerHTML += text;
}
This function works well to use buttons to add strings to a textarea in order to create a complex paragraph.
However, if the user adds/deletes/modifies that text with the keyboard, the function will no longer work until the form is refreshed, which loses the text changes.
Is there a way to modify the function to allow resuming use of the function after any keyboard edits without losing the text that has been added and modified?
Basically a non-jQuery duplicate of Why is my text not being added to the textarea after the second change event? .
innerHTML sets the default value of the textarea. Once the textarea was edited by the user, the current value is stored in the value property.
Use
elem.value += text;
instead.
Related
I've built a page where you can filter results by typing into an input box.
Basic mechanics are:
Start typing, input event is fired, elements without matching text begin hiding
If input becomes empty (or if you click a reset button), all elements are shown again
I have noticed a problem, though, when highlighting text. Say I type "apple" into the input. Then I highlight it, and type "orange."
If an element exists on the page containing "orange," but it was already hidden because I filtered for "apple," it does not show up. I have gathered this is because the input never truly empties; rather, I simply replace "apple" with the "o" from orange before continuing with "r-a-n-g-e." This means I get a subset of "apple" results that contain "orange," as if I had typed "apple orange."
What I really want to do is clear my input on the keypress for the "o" in "orange" before hiding nonmatching elements, so I'm effectively searching the whole page for "orange."
What I've tried so far
1: Set input value to '' on select event:
$('.myinput').on('select', function(){
$(this).val('');
});
This doesn't work because it just deletes my highlighted text, which is unexpected. I only want to reset the input on the keypress following the highlight.
2: Include an if statement in my input event that checks if there is a selection within the input:
$('.myinput').on('input', function(){
var highlightedText = window.getSelection();
if($(highlightedText).parent('.myinput')) {
//reset my input
}
});
This doesn't work because it seems to fire on every keypress, regardless of if there is any actual selection. (Are user inputs always treated as selected?)
3: Add a select event listener to the input element, and set a variable to true if there's a selection. Then, in my input event, check if the variable is true on keypress.
$(function(){
var highlightedText = false;
$('.myinput').on('input', function(){
if(highlightedText = true) {
//reset my input
}
//do stuff
highlightedText = false;
});
$('.myinput').on('select', function(){
highlightedText = true;
});
});
I really thought this one would work because a basic console log in the select function only fires when I want it to – when text in the input is highlighted, but not when other text is highlighted and not when text is entered into the input. But alas, when I change that to a variable toggle, it seems to fire on every keypress again.
So the question is: How can I fire a function on input only if text in my input is highlighted?
I have found this question that suggests binding to the mouseup event, but it seems like overkill to check every single click when I'm only worried about a pretty particular situation. Also, that solution relies on window.getSelection(), which so far isn't working for me.
I've also found another question that suggests to use window.selectionEnd instead of window.getSelection() since I'm working with a text input. I tried incorporating that into option 2 above, but it also seems to fire on every keypress, rather than on highlight.
This answer is not about text selection at all.
But still solve your problem to refilter text when highlighted text is being replaced with new input.
var input = document.getElementById('ok');
var character = document.getElementById('char');
var previousCount = 0;
var currentCount = 0;
input.addEventListener('input', function(){
currentCount = this.value.length;
if (currentCount <= previousCount){
/*
This will detect if you replace the highlighted text into new text.
You can redo the filter here.
*/
console.log('Highlighted text replaced with: ' + this.value);
}
previousCount = currentCount;
char.innerHTML = this.value;
});
<input type="text" id="ok">
<div id="char"></div>
I'll agree with others that you will save yourself some trouble if you change your filtering strategy - I'd say you should filter all content from scratch at each keypress, as opposed to filtering successively the content that remains.
Anyway, to solve your immediate problem, I think you can just get the selection and see if it is empty. You can modify your second attempt:
$('.myinput').on('input', function(){
// get the string representation of the selection
var highlightedText = window.getSelection().toString();
if(highlightedText.length) {
//reset my input
}
});
EDIT
As this solution seems to have various problems, I can suggest another, along the lines of the comment from #Bee157. You can save the old search string and check if the new one has the old as a substring (and if not, reset the display).
var oldSearch = '';
$('.myinput').on('input', function(){
var newSearch = $('.myinput').val();
if (newSearch.indexOf(oldSearch) == -1) {
// reset the display
console.log('RESET');
}
oldSearch = newSearch;
// filter the results...
});
This approach has the added benefit that old results will reappear when you backspace. I tried it in your codepen, and I was able to log 'RESET' at all the appropriate moments.
I have an <input>:
<input type="text" onKeyUp="if(!(event.keyCode>36&&event.keyCode<41)){this.value=check(this.value)}">
And action for it:
function check(num){
num=num.replace(/num/g,"Nº");
return num;
}
JSFIDDLE
The problem is when I assigning value to input the caret jumps to the end. Is it possible to prevent it - I want it to stay where I clicked initially?
Not a JavaScript ninja so I don't know if this is the right way to do this but you could simply update the caret position after replacing the value
In this example, the check function takes the input as an argument:
function check(num) {
var selectionStart = num.selectionStart;
num.value = num.value.replace(/num/g,"Nº");
num.selectionStart = selectionStart;
num.selectionEnd = selectionStart;
}
You can see a working example in this JSFiddle
This may cause strange behaviour if you try to select the whole text using the keyboard (the selection will just disappear). I believe you should make the key code constraints somewhat stricter to avoid that.
I have a <input id="inp" type="text"> that user writes in, and sometimes uses suggests from a dictionary. When a suggest is selected I do:
var input = $('#inp');
input.val(input.val()+suggestedText+' ');
input.focus(); // that is because the suggest can be selected with mouse
everything works great, but when after adding a suggest that makes the resulting input.val() too long to fit in the edit field, the cursor is at the end of the string (which is good), but only the beginning of the string is visible in the edit field, so the cursor is hidden as well.
As soon as a key is pressed (a key that changes the value) the "scroll" goes to the end of the string hiding the beginning... How to trigger this behavior automatically, without having to press a key?
I have found a solution here - but it is not good as the whole input experience is changed...
Have you tried:
var input = $('#inp');
input.val(input.val()+suggestedText+' ');
input.focus(); // that is because the suggest can be selected with mouse
var height=input.contents()[0].outerHeight()
input.animate({
scrollTop:height
},'normal');
?
thank you all for answers, meanwhile I have found sth as well...
when using mouse to click the input lost focus (clik on sth else), and then regained it (thanks to input.focus()) - "scrolling" to the end, but when choosing a suggest was done with a keyboard, focus was never lost, and that is why it was not "scrolling" itself. I just simply added input.blur(), before input.focus(), now works like a charm... have a look at working example
http://46.4.128.78/input/
To make this work you need to set the focus() BEFORE you set the value. You can fix this in many ways, for example:
input.focus(); // that is because the suggest can be selected with mouse
var input = $('#inp');
input.val(input.val() + suggestedText + ' ');
Or this one:
function changeValue(element, newValue) {
element.focus();
element.val(element.val() + newValue + ' ');
}
Basically I need to create a textarea that is character limited, but will have a single word at the beginning, that they can't change.
It needs to be a part of the textarea, but I don't want users to be able to remove it or edit it.
I was thinking I could create a JQuery function using blur() to prevent the user from backspacing, but I also need to prevent them from selecting that word and deleting it.
UPDATE
I wrote this JQuery which seems to work great! However I like the solution below as it requires no Javascript.
<script type="text/javascript">
var $el = $("textarea#message_create_body");
$el.data('oldVal', $el.val());
$el.bind('keydown keyup keypress', function () {
var header = "Header: ";
var $this = $(this);
$this.data('newVal', $this.val());
var newValue = $this.data("newVal");
var oldValue = $this.data("oldVal");
// Check to make sure header not removed
if (!(newValue.substr(0, header.length) === header)) {
$(this).val(oldValue);
} else {
$(this).data('oldVal', $(this).val());
}
});
</script>
If you just want the textarea to show a prefix, you can use a label, change the position, and indent the textarea content. User will not notice the difference.
You can see how it works here: http://jsfiddle.net/FLEA3/.
How about just putting this word as a label next to the textbox? It may be confusing for the users not to be able to edit part of the text in the textbox.
Wouldn't it be better if you just alert the user that whatever he inputs in the textarea will be submitted with a "prefix" and then
show the prefix as a label before the textarea
add the prefix to the inputted text before submitting
I am trying to create a text input field that converts the input text to a "button" onblur. For example in the hotmail "new email page" when you enter email addresses it will make it into a little button-like object with a delete button when you enter a delimiter (semi-colon or comma). Anyone know how to do this?
I did a sort of workaround thing to what i want where i have a div with a border. In the div there is an input field with the borer invisible and a hidden button. I have a js function that takes the input value and makes the button visible with the value but this is not exactly what im looking for..
actually i just realised stackoverflow does this as well when im adding tags to the post
This is a multiple value field. Give a look at this one.
The feature is not so complex. It's an HTML list, and each value that you choose is converted into a LI node and appended to that list. The input field is inside the last LI, so its cursor can always be after the last choice. Besides, the input value is assigned to a hidden input, which can be used on the server-side as a comma-separated value.
Here's a simple way to fake it (and it looks like this is similar to what SO does for tags):
Create your text <input>, and make sure that its border and outline are both set to none.
Create a container for your tags (or buttons, or whatever) and put it next to the <input>.
Monitor the keydown event on the <input>; when the user tries to enter a "break" character (such as a semi-colon or comma), create the button, add it to the container, empty the <input>'s value, and prevent default (so that the "break" character isn't inserted into the tag, or left in the <input>).
That's the basic idea. Once you've done that, you can add event listeners/handlers to the buttons, or style them any which you'd like, etc.
Here's the simple example I cooked up:
var inp = document.getElementById('yourInput'),
tags = document.getElementById('yourContainer'),
breaks = {
186: 1, // semi-colon
188: 1 // comma
};
function createTag(txt) {
var elem = document.createElement('span');
txt = document.createTextNode(txt);
elem.appendChild(txt);
elem.className = 'tag';
tags.appendChild(elem);
}
function monitorText(e) {
e = e || window.event;
e = e.keyCode;
if (breaks[e]) {
e = inp.value;
inp.value = '';
createTag(e);
return false;
}
}
inp.focus();
inp.onkeydown = monitorText;