Get the length of the text in an input in pixels [duplicate] - javascript

I have a input type text
<input type="text" id="txtid">
When i start typing text inside input, i should be able to get the lenght of the entered text.
This is what I tried:
document.getElementById("txtid").offsetWidth;
and
var test = document.getElementById("txtid");
var width = (test.clientWidth + 1) + "px";
These two does not give the width of the text entered
Basically what I want is:
For suppose input text width is 320px. I need the width of the entered text i.e 120px, which keeps on changing when I enter.

I see two ways.
First:
You can use a div with content editable instead input. Like this you can see the width of the div.
var elemDiv = document.getElementById('a');
elemDiv.onblur = function() {
console.log(elemDiv.clientWidth + 'px');
}
div {
width: auto;
display: inline-block;
}
<div id='a' contenteditable="plaintext-only">Test</div>
Note : Like #Leon Adler say, this way allows pasting images, tables and formatting from other programs. So you maybe need some validation with javascript to check the content before get the size.
Second:
Use an input type text and paste the content into an invisible div. And you can see the width of the invisible div.
var elemDiv = document.getElementById('a'),
elemInput = document.getElementById('b');
elemInput.oninput = function() {
elemDiv.innerText = elemInput.value;
console.log(elemDiv.clientWidth + 'px');
}
.div {
width: auto;
display: inline-block;
visibility: hidden;
position: fixed;
overflow:auto;
}
<input id='b' type='text'>
<div id='a' class='div'></div>
Note : For this way, you must have the same font and font size on input and div tags.

I have modified Chillers answer slightly, because it looks like you wanted the width rather than the letter count. I have created a span, which is absolute positioned off the screen. I am then adding the value of the input to it and then getting the width of the span. To make it more fancy you could create the span with javascript.
Note that the input and the span would have to have the same CSS styling for this to be accurate.
document.getElementById("txtid").addEventListener("keyup", function(){
var mrspan = document.getElementById("mrspan");
mrspan.innerText = this.value;
console.log(mrspan.offsetWidth + "px");
});
<input type="text" id="txtid">
<span id="mrspan" style="position:absolute;left:-100%;"></span>

Canvas measureText() method can be helpful in such a case. Call the following function whenever you need to get your text width:
function measureMyInputText() {
var input = document.getElementById("txtid");
var c = document.createElement("canvas");
var ctx = c.getContext("2d");
var txtWidth = ctx.measureText(input.value).width;
return txtWidth;
}
For more accurate result, you may set font styling to the canvas, especially if you set some font properties to the input. Use the following function to get the input font:
function font(element) {
var prop = ["font-style", "font-variant", "font-weight", "font-size", "font-family"];
var font = "";
for (var x in prop)
font += window.getComputedStyle(element, null).getPropertyValue(prop[x]) + " ";
return font;
}
Then, add this line to the frist function:
ctx.font = font(input);

UPDATE
Two things I want to put forward
Doing display none will not give you any offsetWidth if we are trying using vanilla JS. we can use visibility: hidden; or
opacity:0 for that.
we need to add overflow:auto to the hidden span or else the text will be warped to the next line if it exceeds the browser window
width and the width will stay fixed (width of window)
OLD
You can try this approach
Add a span and hide it
<span id="value"></span>
and then onkeyup add the text of the textfield on your hidden span and get its width.
WITH THE HELP OF JQUERY
SNIPPET (UPDATED)
function update(elm,value) {
$('#value').text(value);
var width = $('#value').width();
$('#result').text('The width of '+ value +' is '+width +'px');
}
#value{
display:none;
overflow:auto;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" oninput='update(this,this.value)'>
<span id="value"></span>
<div id="result"></div>
USING JS ONLY
SNIPPET (UPDATED)
function update(elm,value) {
var span = document.getElementById('value');
span.innerHTML = value;
var width = span.offsetWidth;
document.getElementById('result').innerHTML = 'The width of '+ value +' is '+ width+ 'px';
}
#value{
opacity:0;
overflow:auto;
}
<input type="text" oninput='update(this,this.value)'>
<span id="value"></span>
<div id="result"></div>

Using the above solution, I turned it into a single function.
let getWidth = (fontSize, value) => {
let div = document.createElement('div');
div.innerText = value;
div.style.fontSize = fontSize;
div.style.width = 'auto';
div.style.display = 'inline-block';
div.style.visibility = 'hidden';
div.style.position = 'fixed';
div.style.overflow = 'auto';
document.body.append(div)
let width = div.clientWidth;
div.remove();
return width;
};
getWidth('10px', 'test');

Related

How to auto resize the textarea to fit the content?

I'm trying to auto resize the textarea so it fits the content in it but I'm facing a stuttering issue after I click enter to proceed to the next line. How can I fix this?
This is what I'm trying to do, see the image below.
Please see this link for the StackBlitz example
CODE
this.form.valueChanges.subscribe(() => {
const textarea = this.myDiv.nativeElement;
textarea.addEventListener('keydown', function() {
setTimeout(() => {
this.style.cssText = 'height:auto; padding:0';
this.style.cssText = 'height:' + this.scrollHeight + 'px';
}, 0);
});
});
addEventListener here is redundant since valueChanges already notifies you when the field changes. Instead, update the height using the ViewChild reference myDiv.
this.myForm.valueChanges.subscribe(value => {
this.myDiv.nativeElement.style.height = 'auto';
this.myDiv.nativeElement.style.height = `${this.myDiv.nativeElement.scrollHeight}px`;
});
Then add overflow: hidden to your css so the scrollbar doesn't show.
textarea {
resize: horizontal;
overflow: hidden;
}
You can keep the resize: horizontal; but it is no longer required since the textarea will resize automatically anyway.
Here is a working example on StackBlitz.
For anyone still looking for an answer to this in almost 2021, it's covered in the official Angular Material docs here. Directly manipulating the DOM via nativeElement is an anti-pattern.
<mat-form-field [style.fontSize]="fontSize.value">
<mat-label>Autosize textarea</mat-label>
<textarea matInput
cdkTextareaAutosize
#autosize="cdkTextareaAutosize"
cdkAutosizeMinRows="1"
cdkAutosizeMaxRows="5"></textarea>
</mat-form-field>
What you are trying to achieve is a very old trick. I have used it myself but trying a different approach.
It makes more sense why the text area is jumpy coz every keystroke you were making the height = 0 to calculate scroll height so that you can assign a new height.
I calculated the fontSize or lineHeight and calculated number of lines and the initial height to adjust based on that. So on every keystroke you are just assigning height w/o making the text area height=0
textareaProps = null;
getHeight(element) {
const lines = element.value.split(/\r\n|\r|\n/).length;
if(!this.textareaProps) {
const autoStyle = getComputedStyle(element);
const lineHeight = parseInt(autoStyle.lineHeight);
const adjust = parseInt(autoStyle.height) - lineHeight;
this.textareaProps = {adjust, lineHeight}
}
const { adjust, lineHeight } = this.textareaProps;
const height = lines * lineHeight + adjust;
return height + 'px';
}
You now need to call this method to get height and pass the textarea element as arg.
element.style.cssText = 'height:' + getHeight(element) ;
Edit 2
Sadly the above solution will only work if there are line breaks by user. When you enter a huge line text area wraps it but it doesn't increase the height. So intruducing a proxy html element which will have the text as same as text area value and will provide a height that we can assign to our text area.
textareaProps = null;
getHeight(element) {
if(!this.textareaProps) {
const proxy = document.createElement('div');
const {padding, width, fontSize, height, lineHeight} = getComputedStyle(element);
const css = [
'position:absolute',
'visibility: hidden',
'pointer-events:none',
`width: ${width}`,
`padding:${padding}`,
`min-height: ${height}`,
`font-size:${fontSize}`,
`line-height:${lineHeight}`,
].join(';');
proxy.style.cssText=css;
this.textareaProps = {
proxy: document.body.appendChild(proxy),
adjust: (parseInt(fontSize))
};
}
const { proxy, adjust} = this.textareaProps;
proxy.innerText = element.value + '.';
return (proxy.offsetHeight + adjust) + 'px';
}
Updated StackBlitz https://stackblitz.com/edit/next-line-view-child-ssnp4q
<textarea rows="15" id="code" disabled placeholder="Description"></textarea>
rows="15" to set min heigth to 15 rows
el = document.getElementById("code");
el.style.height = "auto";
// code to populate textarea
el.style.height = (5 + el.scrollHeight) + "px";
this helped me to set textarea to height as per content populated in it.
If you dont want a plugin there is a very simple solution
$(document).ready(function() {
$('textarea').on('keyup keypress', function() {
$(this).height(0);
$(this).height(this.scrollHeight);
});
$("textarea").each(function(textarea) {
$(this).height(0);
$(this).height(this.scrollHeight);
});
});

Get input text width when typing

I have a input type text
<input type="text" id="txtid">
When i start typing text inside input, i should be able to get the lenght of the entered text.
This is what I tried:
document.getElementById("txtid").offsetWidth;
and
var test = document.getElementById("txtid");
var width = (test.clientWidth + 1) + "px";
These two does not give the width of the text entered
Basically what I want is:
For suppose input text width is 320px. I need the width of the entered text i.e 120px, which keeps on changing when I enter.
I see two ways.
First:
You can use a div with content editable instead input. Like this you can see the width of the div.
var elemDiv = document.getElementById('a');
elemDiv.onblur = function() {
console.log(elemDiv.clientWidth + 'px');
}
div {
width: auto;
display: inline-block;
}
<div id='a' contenteditable="plaintext-only">Test</div>
Note : Like #Leon Adler say, this way allows pasting images, tables and formatting from other programs. So you maybe need some validation with javascript to check the content before get the size.
Second:
Use an input type text and paste the content into an invisible div. And you can see the width of the invisible div.
var elemDiv = document.getElementById('a'),
elemInput = document.getElementById('b');
elemInput.oninput = function() {
elemDiv.innerText = elemInput.value;
console.log(elemDiv.clientWidth + 'px');
}
.div {
width: auto;
display: inline-block;
visibility: hidden;
position: fixed;
overflow:auto;
}
<input id='b' type='text'>
<div id='a' class='div'></div>
Note : For this way, you must have the same font and font size on input and div tags.
I have modified Chillers answer slightly, because it looks like you wanted the width rather than the letter count. I have created a span, which is absolute positioned off the screen. I am then adding the value of the input to it and then getting the width of the span. To make it more fancy you could create the span with javascript.
Note that the input and the span would have to have the same CSS styling for this to be accurate.
document.getElementById("txtid").addEventListener("keyup", function(){
var mrspan = document.getElementById("mrspan");
mrspan.innerText = this.value;
console.log(mrspan.offsetWidth + "px");
});
<input type="text" id="txtid">
<span id="mrspan" style="position:absolute;left:-100%;"></span>
Canvas measureText() method can be helpful in such a case. Call the following function whenever you need to get your text width:
function measureMyInputText() {
var input = document.getElementById("txtid");
var c = document.createElement("canvas");
var ctx = c.getContext("2d");
var txtWidth = ctx.measureText(input.value).width;
return txtWidth;
}
For more accurate result, you may set font styling to the canvas, especially if you set some font properties to the input. Use the following function to get the input font:
function font(element) {
var prop = ["font-style", "font-variant", "font-weight", "font-size", "font-family"];
var font = "";
for (var x in prop)
font += window.getComputedStyle(element, null).getPropertyValue(prop[x]) + " ";
return font;
}
Then, add this line to the frist function:
ctx.font = font(input);
UPDATE
Two things I want to put forward
Doing display none will not give you any offsetWidth if we are trying using vanilla JS. we can use visibility: hidden; or
opacity:0 for that.
we need to add overflow:auto to the hidden span or else the text will be warped to the next line if it exceeds the browser window
width and the width will stay fixed (width of window)
OLD
You can try this approach
Add a span and hide it
<span id="value"></span>
and then onkeyup add the text of the textfield on your hidden span and get its width.
WITH THE HELP OF JQUERY
SNIPPET (UPDATED)
function update(elm,value) {
$('#value').text(value);
var width = $('#value').width();
$('#result').text('The width of '+ value +' is '+width +'px');
}
#value{
display:none;
overflow:auto;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" oninput='update(this,this.value)'>
<span id="value"></span>
<div id="result"></div>
USING JS ONLY
SNIPPET (UPDATED)
function update(elm,value) {
var span = document.getElementById('value');
span.innerHTML = value;
var width = span.offsetWidth;
document.getElementById('result').innerHTML = 'The width of '+ value +' is '+ width+ 'px';
}
#value{
opacity:0;
overflow:auto;
}
<input type="text" oninput='update(this,this.value)'>
<span id="value"></span>
<div id="result"></div>
Using the above solution, I turned it into a single function.
let getWidth = (fontSize, value) => {
let div = document.createElement('div');
div.innerText = value;
div.style.fontSize = fontSize;
div.style.width = 'auto';
div.style.display = 'inline-block';
div.style.visibility = 'hidden';
div.style.position = 'fixed';
div.style.overflow = 'auto';
document.body.append(div)
let width = div.clientWidth;
div.remove();
return width;
};
getWidth('10px', 'test');

Animate text area to fit the contents of the text area

I want to resize the textarea to fit the contents of the text area.
I am currently using the following code to do that:
var element = document.getElementById(event.target.id);
var content = $(this).val().trim();
if (content == "") {
$(this).animate({
width: element.scrollWidth,
height: element.scrollHeight
}, 100);
}
When I enter nothing. I expect the textarea to become smaller in size and eventually disappear.
But it is expanding instead. :(
JSFiddle: http://jsfiddle.net/7vfjet1g/
I think what you're looking for is an elastic text area. There are a few JavaScript libraries that provide this functionality:
https://github.com/chemerisuk/better-elastic-textarea
https://github.com/chrisgeo/elastic-textarea
http://unwrongest.com/projects/elastic/
It's not much code, but a careful combination of JavaScript and CSS. If for some reason you don't want to add another library to your project, or this doesn't fit your requirement, it may point you in the right direction. Good luck.
I tested out your existing code, and the values that scrollWidth and scrollHeight were giving you were much bigger than the size of the actual text.
One way to get the size of the actual text is to create a span with the same font styling as the text area, copy over the value of the textarea to it, then append the span to the document. You can then use getBoundingRect() to get the dimensions of the span, and thus the dimensions of the text in your textarea.
NOTE: I changed the id of your enclosing div. It had the same id as the textarea, and ids are supposed to be unique. Having two elements with the same id could cause problems with the javascript. Here's the jsfiddle: https://jsfiddle.net/yog8kvx7/7/. And here's the updated blur function:
$('.notesArea').blur(function (event)
{
var content = $(this).val().trim();
var element = document.getElementById(event.target.id);
// Create span to calculate width of text
var span = document.createElement('span');
// Set position to absolute and make it hidden
// so it doesn't affect the position of any other elements
span.style.position = 'absolute';
span.style.visibility = 'hidden';
// Only set to whitespace to pre if there's content
// "pre" preserves whitespace, including newlines
if (element.value.length > 0)
span.style.whiteSpace = 'pre-wrap';
// Copy over font styling
var fontStyle = window.getComputedStyle(element);
span.style.display = 'inline-block';
span.style.padding = fontStyle.padding;
span.style.fontFamily = fontStyle.fontFamily;
span.style.fontSize = fontStyle.fontSize;
span.style.fontWeight = fontStyle.fontWeight;
span.style.lineHeight = fontStyle.lineHeight;
span.innerHTML = element.value;
// Add to document and determine width
document.body.appendChild(span);
var rect = span.getBoundingClientRect();
var width = rect.width;
var height = rect.height;
// Remove span from document
span.parentNode.removeChild(span);
$(this).animate({
width: width,
height: height
}, 100);
});
And if you want to account for the little sizing handle, so it doesn't cover the text, you can just add an offset to the width to account for it.

How to set the font-size to 100% the size of a div?

I have a div with a static size. Sometimes longer text than the div will be placed there. Is there anyway to achieve the text fitting the div width at all times through JavaScript alone? I am aware there are jQuery fixes but need a pure JS solution in this case.
Even if you have a link to a demo/tutorial that would be helpful, thanks.
Here you go, this should do what you want: JSFiddle
Basically the key here is to check the output.scrollHeight against output.height. Consider the following setup:
HTML:
<button onclick="addText(); resizeFont()">Click Me to Add Some Text!</button>
<div id="output"></div>
CSS:
div {
width: 160px;
height: 160px;
}
This creates a square div and fills it with a randomly long string of text via the addText() method.
function addText() {
var text = "Lorem ipsum dolor amit",
len = Math.floor(Math.random() * 15),
output = document.querySelector('#output'),
str = [];
for (; --len;)
str.push(text);
output.innerHTML = str.join(', ');
}
The magic lies in the resizeFont() function. Basically what this does is, once the text has been added, it sets the fontSize of the div to be equal to its own height. This is the base case for when you have a string of 1 character (i.e. the fontSize will equal the height). As the length of your string grows, the fontSize will need to be made smaller until the scrollHeight equals the height of the div
function resizeFont() {
var output = document.querySelector('#output'),
numRE = /(\d+)px/,
height = numRE.exec(window.getComputedStyle(output).height)[1],
fontSize = height;
// allow div to be empty without entering infinite loop
if (!output.innerHTML.length) return;
// set the initial font size to the height of the div
output.style.fontSize = fontSize + 'px';
// decrease the font size until the scrollHeight == height
while (output.scrollHeight > height)
output.style.fontSize = --fontSize + 'px';
}
The nice thing about this method is that you can easily attach an event listener to the resize event of the window, making the text dynamically resize as the user changes the window size: http://jsfiddle.net/QvDy8/2/
window.onload = function() {
window.addEventListener('resize', resizeFont, false);
}

Trying to add a "ghost" text in a input form with javascript

I found something i like on Tumbler and tried to recreate it.. but i have a problem.
this is what im trying to clone:
http://cl.vc/Beta/Tumbler/
and this is what i have:
http://cl.vc/Beta/Tumbler/test.html
HTML:
<form method="post" name="form" id="form">
<span id="myText"><p hidden>good</p></span>
<input type="text" id="input" name="input" value="" onkeypress="showtext();"/>
JavaScript:
function showtext() {
var inputlength = document.getElementById('input').value.length;
var string = "";
for (var i = 0; i <= inputlength; i++) {
var string = string + " ";
}
document.getElementById('myText').innerHTML = string + "cl.vc";
document.getElementById('myText').style.zIndex = "2";
}
the problem is that the space is not the same as if you type in hhhhh or iiiiii because the size of the letter is different.. i also would like if to take away the space if you delete the text..
Put the text in another div and measure the width, using the answer here: Determine Pixel Length of String in Javascript/jQuery?
Then, set your suffix to start at the offset you determined from the width
Create a DIV styled with the following styles. In your JavaScript, set the font size and attributes that you are trying to measure, put your string in the DIV, then read the current width and height of the DIV. It will stretch to fit the contents and the size will be within a few pixels of the string rendered size.
HTML:
<div id="Test">
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
</div>
CSS:
#Test
{
position: absolute;
visibility: hidden;
height: auto;
width: auto;
}
JavaScript (fragment):
var test = document.getElementById("Test");
test.style.fontSize = fontSize;
var height = (test.clientHeight + 1) + "px";
var width = (test.clientWidth + 1) + "px";

Categories

Resources