8

I am trying to truncate a long string for display only on my index page. It is shown like so:

<td>
    @Html.DisplayFor(modelItem => item.Description)
</td>

The Description can be 500 characters long but I can't show that much on that grid layout. I'd like to show just the first 25 as they can see all of it on the Details page but I cannot seem to get it to work with out truncating it at the model level.

Something like this would be nice:

@Html.DisplayFor(modelItem => item.Description.Take(25))
@Html.DisplayFor(modelItem => item.Description.Substring(0,25)

EDIT

I'm getting the following exception at Runtime when I try either method.

Templates can be used only with field access, property access, single-dimension array index, or single-parameter custom indexer expressions.
Refracted Paladin
  • 12,096
  • 33
  • 123
  • 233
  • Have you considered creating an additional model property that performs the substring and using that? – Mike Cheel May 09 '14 at 19:48
  • Yeah, that was how I was going to do it if there wasn't a way to work with the Templates and single property. – Refracted Paladin May 09 '14 at 19:52
  • Your specific problem here is that the expression passed into `Html.DisplayFor` must reference an actual property, not a specific value. In other words, you can only do `@Html.DisplayFor(m => item.Description)`, not `@Html.DisplayFor(m => item.Description.Substring(0, 25))`. You don't need to use `Html.DisplayFor` for this, though, so you can just write `@item.Description.Substring(0, 25)`. However, bear in mind @48klocs's comment to Nathan A's answer. – Chris Pratt May 09 '14 at 20:03
  • 1
    Note that `Take()` returns a `IEnumerable`, not a string. `Substring()` is more suited for this. – Nathan A May 09 '14 at 20:05

7 Answers7

27

Don't use the html helper. Just do this:

@item.Description.Substring(0, Math.Min(item.Description.Length, 25));

I'm assuming you are in some loop where item is the current element.

Nathan A
  • 11,059
  • 4
  • 47
  • 63
  • 2
    That will throw an `ArgumentOutOfRangeException` if the string isn't longer than 25 characters. – 48klocs May 09 '14 at 19:43
  • @NathanA , this works great, but can you provide option 2 to show dots at the end like this `mydescription .....` , i tried [this](http://stackoverflow.com/questions/4610199/asp-net-mvc-substring-help) and gives error when parsed, do you have any idea? – Shaiju T May 02 '15 at 13:29
  • @NathanA thank you so much. I was struggling with this since 2 hours finally got the solution – Sumedha Vangury Apr 07 '16 at 07:50
7

You could do this with an extension method.

public static string Truncate(this string source, int length)
{
    if (source.Length > length)
    {
        source = source.Substring(0, length);
    }

    return source;
}

Then in your view:

@item.Description.Truncate(25)
48klocs
  • 6,073
  • 3
  • 27
  • 34
  • That still won't work. DisplayFor only accepts expressions that result in a value (specifically what's listed in the error), not method calls. That's what is generating the *Templates* error. – Nathan A May 09 '14 at 19:46
  • @NathanA you're probably right. I didn't check what the call for `DisplayFor` vs. `Display` was. I think a named `Display` element should work, but I'm just guessing there. – 48klocs May 09 '14 at 19:48
  • That looks better. Good general application. – Nathan A May 09 '14 at 19:55
4

you could either truncate the data before it gets to the View, or use this Razor:

@{
    var shortDescript = String.Concat(modelItem.Take(25));
}
@Html.DisplayFor(modelItem => shortDescript)
arserbin3
  • 6,010
  • 8
  • 36
  • 52
  • While that may work, why would you use `DisplayFor` at all then? Any benefit you would get using it on a member of your data model is lost doing it this way. – Nathan A May 09 '14 at 20:00
  • Assuming the type did not change (string to string), you can still make use of the same display template. See http://stackoverflow.com/a/6365658/1445356 – arserbin3 May 09 '14 at 20:02
1

You might consider creating a special model property for such instances where you need this:

public class MyModel
{
    public string MyDescription {get; set;}
    public string MyShortDescription {
        get 
        {
              return Truncate(MyDescription, 25);
        }
}

private string Truncate(string, howMany)
{
   // Code to perform the substring here
}

@Html.DisplayFor(modelItem => item.MyShortDescription);
Mike Cheel
  • 12,626
  • 10
  • 72
  • 101
1

Try this if you want to use the HTML helpers. Say you want to get part of a string before the first space .IndexOf(' ') (or you can just use a predefined index 25 like u said):

@Html.DisplayFor(modelItem => item.Description).ToString().Substring(0,item.Description.IndexOf(' '))
user3590235
  • 153
  • 7
1

The HTML helper for ASP Net Core 3 MVC.

public static HtmlString Truncate(this IHtmlHelper helper, string text, int maxLength = 100)
{
    if (text == null) return new HtmlString("");

    if (text.Length > maxLength)
    {
        text = text.Substring(0, maxLength) + "...";
    }
    return new HtmlString($"{text}");
}

Use in cshtml file

@Html.Truncate(item.Description)

Or you can use param

@Html.Truncate(item.MusicUrl, 50)
dev-siberia
  • 2,746
  • 2
  • 21
  • 17
0

Try an extension

public static string TruncateMiddle(this string value, int lengthExpected, string separator = "...")
    {
        if (value.Length <= lengthExpected) return value;

        decimal sepLen = separator.Length;
        decimal charsToShow = lengthExpected - sepLen;
        decimal frontChars = Math.Ceiling(charsToShow / 2);
        decimal backChars = Math.Floor(charsToShow / 2);

        return value.Substring(0, (int)frontChars) + separator + value.Substring(value.Length - (int)backChars);            
    }

Use

MyLongString.TruncateMiddle(50)

Return something like this: Lorem ipsum dolor sit ame...onsectetur cras amet.

Yarag
  • 1
  • 1