views:

192

answers:

8

I'm writing a mobile web application where scrollbars are not displayed on the device's browser. Due to this, I'm trying to dynamically modify the height of the textarea to make it bigger, however I don't know of any way to actually get the line count on an html textarea. Any help would be greatly appreciated!

EDIT

So I realize now that it's not newlines per se, but actual line wrapping. So when one line finishes it wraps the text to the next line. It appears as if it is a new line. Any way to count the number of these? Thanks!

A: 

The number of lines in the textarea would be

textarea.value.match(/\n/g).length + 1
Delan Azabani
I'm doing $(nameofthetextareaid).val().match(/\n/g) and am receiving null from the debugger. I tried it with /\n/g in quotes as well.
Kyle
Try the plain JavaScript solution I gave you, instead of using jQuery?
Delan Azabani
I realize now that it's line wrapping not new lines. The solution you gave did work though for newlines.
Kyle
A: 

Untested, but try this:

var linecount = document.getElementById("myTextarea").value.split("\n").length;

Edit

To detect lines that wrap into the next line, this is the general process:

  • Calculate the average width of a character, as displayed by the textarea
  • For each line, estimate the width of the line
  • If this width is greater than the width of the

Here is the code I came up with (I will be turning this into a full-fledged jQuery plugin, by the way):

(function($){
    $.countLines = function(textarea){
    // The textarea
    var ta;

    if (typeof textarea == "string")
        ta = $(textarea);
    else if (typeof textarea == "object")
        ta = textarea;

    // Generate a span after the textarea with a random ID
    var id = "";
    for ( var i = 1; i <= 10; i++)
        id += (Math.floor(Math.random() * 10) + 1);

    ta.after("<span id='s" + id + "'></span>");
    var span = $("#s" + id);

    // Hide the span
    span.hide();

    // Apply the font properties of the textarea to the span class
    $.each(["font-family", "font-size", "text-decoration", "font-style", "font-weight"], function(i, v){
        span.css(v, ta.css(v));
    });

    // Get the textarea value
    var value = ta.val();

    // Get the number of lines
    var lines = value.split("\n");
    var linesLen = lines.length;

    // Get a pretty good estimation of the width of a character in the textarea. To get a better average, add more characters and symbols to this list
    var chars = ["D", "E", "C", "I", "D", "Q", "?", "!", ".", ","];

    var charLen = chars.length;
    var totalWidth = 0;

    $.each(chars, function(i, v){
        span.text(v);
        totalWidth += span.width();
    });

    // Calculate average width of character
    var averageWidth = Math.ceil(totalWidth / charLen);

    // Determine missing width (from padding, margins, borders, etc); this is what we will add to each line width
    var missingWidth = (ta.outerWidth() - ta.width()) * 2;

    // Calculate the number of lines that occupy more than one line
    var lineWidth;

    var wrappingLines = 0;

    $.each(lines, function(i, v){
        // Calculate width of line
        lineWidth = (v.length * averageWidth) + missingWidth;
        // Check if the line is wrapped
        if (lineWidth > ta.outerWidth())
        wrappingLines++;
    });

    var ret = {};
    ret["actual"] = linesLen;
    ret["wrapped"] = wrappingLines;
    ret["visual"] = linesLen + wrappingLines;

    return ret;
    };
})(jQuery);

To use it:

alert($.countLines($("#ta")).wrapped);

... will give the number of times a line wraps (but only once per line, in my plugin I will fix this shortcoming).

Also, alert($.countLines($("#ta")).actual); gives total lines, whether they wrap or not and

alert($.countLines($("#ta")).visual); will give the total lines plus wrapped lines. Hope you find this useful, and be sure to check back in the next day or two as I will post a link to the plugin when I finish it.

SimpleCoder
This did work, however I'm realizing now that it's not newlines in the nextarea but actually wrapping onto the next line. When I actually added a few some blank lines I got more values from split. Is there any way to detect how many times the input has wrapped to the next line?
Kyle
See my edit... I posted a solution
SimpleCoder
@Kyle: Instead of the code I posted in my answer, use my plugin: http://mosttw.wordpress.com/2010/09/14/textarea-line-count-jquery-plugin/
SimpleCoder
+1  A: 

I'm pretty sure there is no reasonable way to count the number of lines as displayed in the browser especially considering some browsers (Safari) allow the user to resize textareas.

It'd be hacky, but your best bet might be to just estimate based on the total characters divided by average number of characters per line. :-/

tfe
That's what I tried before, but it always messed up in special cases
Kyle
Yeah, that's why I said "hacky" and "estimate." :-/ I don't think there's any other way to do it given the limitations. Maybe you can re-evaluate if there's any better input method for what you're trying to do? Textarea doesn't seem to fit your requirements.
tfe
A: 

The number of characters allowed per line is dictated by the "cols" attribute of the textarea.

<textarea rows="10" cols="80"></textarea>

Assuming 80 characters per line, a good estimate may be:

var approxNumLines = textareaElement.value.length / textareaElement.cols ;

Doesn't account for word-break and word-wrap.

bobobobo
It doesn't obey the cols attribute as it says the cols value is 20, and when I look at the value's length it's up to 70 at times.
Kyle
it is better to use `width` and `height` in place of `cols` and `rows`
SimpleCoder
+2  A: 

I haven't tried using the function discussed in this blog, but you may find it useful.

http://kirblog.idetalk.com/2010/03/calculating-cursor-position-in-textarea.html

Basically, if you create a div and then copy the text into that div, with the same width and font characteristics, you can then get the information you need, such as the number of lines. The number of lines in this example would be easy, in that if you know how many pixels high a single line would be, then just find the width of the test div and you can get a pretty accurate idea as to how many lines are in your textarea.

James Black
A: 

Maybe there is a way to get the "raw" number of "visual" lines. You should read the scrollHeight property of the textarea and divide it by the height of a line. Let's try.

Start with this HTML:

<textarea id="ta" cols="50" rows="10"></textarea>

Then:

var line_height = Math.floor($("#ta").height() / parseInt($("#ta").attr("rows")));
var dirty_number_of_lines = Math.ceil($("#ta")[0].scrollHeight / line_height);

I am not sure if that really works, just a mad theory.

floatless
line-height is a CSS attribute, you should be able to obtain it without resorting to math (the textbox height is not guaranteed to be a multiple of the line height, anyway).
Tgr
No, just `line-height` is not sufficient in this task. I cannot just take `line-height` and divide by it. I have to calculate the height of lines in the `textarea` manually because `font-size` may vary too.
floatless
A: 

Get scrollHeight, subtract top+bottom padding, divide by lineHeight.

Tgr
A: 

I have created a plugin to handle line counting and wrap detection in a textarea: http://mosttw.wordpress.com/2010/09/14/textarea-line-count-jquery-plugin/.

Example:

var result = $.countLines("#textarea");

result.actual   // The number of lines in the textarea.
result.wraps    // The number of lines in the textarea that wrap at least once.
result.wrapped  // The total number of times all lines wrap.
result.blank    // The approximate number of lines that the user actually sees in the textarea
result.visual   // The number of blank lines.

I hope someone can use it.

SimpleCoder