3

I have a ternary operator in my MVC4 View:

@(modelrecord.Website == null ? "" : modelrecord.Website.Replace("http://","") )

This works, but I want to make the website record a hyperlink. Is this possible?

Note: I'm replacing the "http://" prefix because it's ugly.

If I put in the actual string with Html.Raw, the angle brackets are escaped, and I still don't get a link.

northben
  • 5,448
  • 4
  • 35
  • 47

1 Answers1

3

You should probably be using DataAnnotations and the @Html.DispayFor helper.

public class ModelRecord
{
    [DataType(DataType.EmailAddress)]
    public String EmailAddress { get; set; }

    [DataType(DataType.Url)]
    public String Website { get; set; }
}

Then:

email me at @Html.DisplayFor(x => x.EmailAddress)
or visit me online at @Html.DisplayFor(x => x.Website)

The DataTypeAttribute handles things like urls, emails, etc. and formats them depending.

If you want to customize all Urls, you can create a display template for it:

~/Views/Shared/DisplayTemplates/Url.cshtml

@model String
@if (!String.IsNullOrEmpty(Model))
{
    <a href="@Model">@Model.Replace("http://", "")</a>
}
else
{
    @:Default text when url is empty.
}

DisplayTemplates (like EditorTemplates) is a convention-based path that MVC uses. because of this, you can place the template in the Shared directory to apply this change site-wide, or you can place the folder within one of the controller folders to only have it apply to that controller (e.g. ~/Views/Home/Displaytemplates/Url.cshtml). Also, Url is one of the pre-defined templates included for use with DisplayType, along with the following:

  • Url
  • EmailAddress
  • HiddenInput
  • Html
  • Text
Brad Christie
  • 100,477
  • 16
  • 156
  • 200
  • Excellent. Thank you very much. I had to use `@Html.DisplayFor(x => modelrecord.Website) instead though - this answer explained it: http://stackoverflow.com/questions/10097995/i-want-to-understand-the-lambda-expression-in-html-displayformodelitem-mymo – northben Apr 12 '13 at 14:54
  • @northben: Indeed. I didn't know the structure of your VM, but was showing how you would format a value in the simplest way possible. As was your case, you'd have to reference a property off a nested object of the model (and you see how) but the premise and decoration(s) are the same. – Brad Christie Apr 12 '13 at 14:56
  • are you sure the `x => x.Website` would work for any model though? I'm obviously new to this, but it seems the first x 'overwrites' the second in this 'parameterless' lambda. – northben Apr 12 '13 at 15:00
  • Assuming the page accepts `ModelRecord` (`@model ModelRecord`) the lambda is going to reference `x` as if it's `Model`. However it changed when you start getting in to nested objects or custom objects. e.g. if I had a `IEnumerable Profiles` property in the model and stored `var profile = Model.Profiles[i];` I would use `@Html.DisplayFor(x => profile.Name)` (but could also use `@Html.DisplayFor(x => x.Profiles[i].Name)` (confused yet?)) – Brad Christie Apr 12 '13 at 15:06
  • actually that does make sense. I didn't know that `x` referenced the model type declared in my View. That was always a bit of a mystery to me actually. And I am indeed in a nested model. – northben Apr 12 '13 at 15:08
  • `DisplayFor` is defined as `DisplayFor`, where `TModel` is provided by `@model`. You can pass it another objects (it's an expression after all) but intellisense is going to assume the `TModel` type first. ([source code](https://aspnetwebstack.codeplex.com/SourceControl/changeset/view/556493386c463f0e831298c65784e545b89ff287#src/System.Web.Mvc/Html/DisplayExtensions.cs) if you're interested) – Brad Christie Apr 12 '13 at 15:13