MVC3, Razor, Html.TextAreaFor(): adjust height to fit contents
Solution 1
The code looks fine. One possible improvement would be to externalize it into a reusable helper to avoid polluting the view:
public static class TextAreaExtensions
{
public static IHtmlString TextAreaAutoSizeFor<TModel, TProperty>(
this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> expression,
object htmlAttributes
)
{
var model = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData).Model;
var text = model as string ?? string.Empty;
int width = 85;
int lines = 1;
string[] arr = text.Split(new string[] { "\r\n", "\n", "\r" }, StringSplitOptions.None);
foreach (var str in arr)
{
if (str.Length / width > 0)
{
lines += str.Length / width + (str.Length % width <= width / 2 ? 1 : 0);
}
else
{
lines++;
}
}
var attributes = new RouteValueDictionary(htmlAttributes);
attributes["style"] = string.Format("width:{0}em; height:{1}em;", width, lines);
return htmlHelper.TextAreaFor(expression, attributes);
}
}
and in the view:
@Html.TextAreaAutoSizeFor(m => m.Text, new { id = "text" })
Solution 2
That looks great, you can also use the JQuery autogrow textarea plugin.
It will save you some coding, and may even be more efficient.
Solution 3
You can reduce this to one line with some LINQ magic:
var lines = Model.Text.Split( new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None )
.Aggregate( 0, (total, next) =>
total += next.Length <= width ? 1
: (int)Math.Ceiling( (double)next.Length / width ) );
Note that there's a wee problem with the way you're splitting. If there really are mixed \n
, \r
, and \r\n
line endings in your input (unlikely), this split will split in order from left to right, so it won't ever split on the string \r\n
, which will mean an empty line between the \r
and the \n
. So you'll see I moved the \r\n
as the first string in the split.
Handprint
Technologies/Skill Sets: .NET, MVC(VM), NHibernate, EntityFramework, Parallel Computing Education: B.S. Computer Science, B.A. English Lit Current Studies: Design Patterns, openSuse+Apache+Mono+MariaDB+ASP.NET MVC, TFD/TDD
Updated on November 22, 2022Comments
-
Handprint over 1 year
I'm currently using the following code in the View to adjust the height of a Html.TextAreaFor() to fit its contents. Is there a significantly better &/or less verbose way to do this?
... int width = 85; int lines = 1; string[] arr = Model.Text.Split(new string[] {"\r\n", "\n", "\r"}, StringSplitOptions.None); foreach (var str in arr) { if (str.Length / width > 0) { lines += str.Length / width + (str.Length % width <= width/2 ? 1 : 0); } else { lines++; } } @Html.TextAreaFor(m => m.Text, new { id = "text", style = "width:" + width + "em; height:" + lines + "em;" }) ...
-
Handprint almost 12 yearsGreat plugin. Torn between this answer and Darin Dimitrov's! Might be a wee bit fancier than I need.
-
Ethan Brown almost 12 yearsRight you are; I corrected this problem in the answer. Good catch!
-
Handprint almost 12 yearsReusable, makes maintenance easier, and unclutters the view... and works like a charm! Just had to add the using directives: using System.Web.Routing; using System.Web.Mvc; using System.Web.Mvc.Html; using System.Linq.Expressions;
-
Handprint almost 12 yearsThanks for the fix. Compact and works! Used it in conjunction with Darin's answer.