42

Whilst looking at a theme I downloaded from the Orchard CMS gallery, I noticed that a Layout.cshtml file had this block of code at the top of the file:

@functions {
// To support the layout classifaction below. Implementing as a razor function because we can, could otherwise be a Func<string[], string, string> in the code block following.
string CalcuClassify(string[] zoneNames, string classNamePrefix)
{
    var zoneCounter = 0;
    var zoneNumsFilled = string.Join("", zoneNames.Select(zoneName => { ++zoneCounter; return Model[zoneName] != null ? zoneCounter.ToString() : ""; }).ToArray());
    return HasText(zoneNumsFilled) ? classNamePrefix + zoneNumsFilled : "";
}
}

I know what the declared function does (calculates which zones are populated in order to return the width of each column), my question is- what is the correct use of the @function block, and when should I ever use it?

Chris Payne
  • 1,690
  • 1
  • 17
  • 32
  • Personally I think it should be avoided as it just muddies the waters in what is you presentation/view layer and what is your business controller/layer. – Liam Dec 20 '12 at 15:27
  • 12
    @Liam - I disagree. I think it should expressly be used for purposes of *avoiding* muddying the waters. In this example, it's for purposes of determining column width, which is not something the controller should even know about. – Bobson Dec 20 '12 at 15:30

4 Answers4

57

The @functions block lets you define utility functions directly in the view, rather than adding them as extensions to the @Html helper or letting the controller know about display properties. You'd want to use it when you can meet these conditions:

  1. The functionality is tied closely to the view and is not generally useful elsewhere (such as "How wide do I make my columns").
  2. The functionality is more than a simple if statement, and/or is used in multiple places in your view.
  3. Everything that the function needs to determine it's logic already exists in the Model for the view.

If you fail the first one, add it as a @Html helper.

If you fail the second one, just inline it.

If you fail the third one, you should do the calculation in your controller and pass the result as part of the model.

Bobson
  • 12,858
  • 4
  • 49
  • 78
  • +1. This is a great answer. There is a case for using `@functions`, but not very often! – Tom Chantler Dec 20 '12 at 16:04
  • 3
    Great answer, especially the part about explaining alternatives you should use :D – Rory McCrossan Dec 20 '12 at 17:19
  • hi Bobson, you mean we can't use @functions block in other files? – Georgi Kovachev Dec 01 '16 at 22:18
  • @GeorgiKovachev - As far as I know, that's correct. The contents of an function block are only valid in the same file. I've never actually tried it, though, so it's possible there's some variant you can use to include a different file's functions. I'd find it very strange, though. – Bobson Dec 01 '16 at 23:21
  • 1
    @GeorgiKovachev you can create `Razor helpers`, instead of `functions`, if you want to use them in other ***Views***. Do no forget to place those ***@helper***_s_ in `App_Code` in order to make them globally visible. Then you can use those helpers in any View, by prepending them with filename which contains that Razor helper. – AlexMelw May 10 '18 at 10:04
6

Others have explained what @functions does so I won't rehash that. But I would like to add this:

If your view is typed to a viewmodel, I think a viable option would be to move this logic into the viewmodel to avoid cluttering your markup with too much code. Otherwise your views start to look more and more like classic ASP and I don't think anybody wants that.

I don't think there's anything wrong with using @functions or @helper in your view, but once you get beyond a couple of methods in your view, or even if the function is somewhat complicated, it might be worth refactoring to the viewmodel if at all possible. If it's code that can be reused, it may be a good idea to to pull it out into a helper class or an extension to the HtmlHelper class. One thing that is a bummer is realizing you just rewrote a piece of code that already existed because you didn't know it was hidden away in some arbitrary view.

hawkke
  • 4,152
  • 1
  • 25
  • 23
0

From msdn blogs, @functions block is to let you wrap up reusable code, like the methods and properties

indiPy
  • 7,115
  • 3
  • 25
  • 39
0

In this particular case, the people who have created the theme you are using probably were trying to keep it as a simple theme (only views, css and images).

If you need to write some code for a theme for Orchard, you have to turn to a module (as stated here: http://docs.orchardproject.net/Documentation/Anatomy-of-a-theme) unless you write this code in the view.

I am not sure it is worth the time to switch from a theme to a module only to get the size of a column.

cheesemacfly
  • 10,986
  • 11
  • 45
  • 69