Shaun Luttin
Shaun Luttin

Reputation: 141452

Create a method/function to use within a view

How can we write a function to use in a *.cshtml page. We used to be able to use @helper or @function within the view. How do we do this? For instance, I would like to write a recursive function to show all configuration values. How could I do this?

<dl>
    @foreach(var k in config.GetSubKeys())
    {
        <dt>@k.Key</dt>
        <dd>@config.Get(k.Key)</dd>
        @* TODO How can we make this a helper function/recursive? *@
        @foreach(var sk in config.GetSubKey(k.Key).GetSubKeys())
        {
            <dt>@sk.Key</dt>
            <dd>@config.Get(sk.Key)</dd>
        }
    }
</dl>   

I imagine that we need to add a dependency in project.json and then opt-in to using it in Startup.cs.

Upvotes: 4

Views: 3395

Answers (2)

mitsbits
mitsbits

Reputation: 325

Quick and dirty using razor views assuming your view component provides a recursive model.

Component view:

@model YourRecursiveDataStructure
<ul class="sidebar-menu">
    <li class="header">MAIN NAVIGATION</li>

    @foreach (var node in Model.RootNodes)
    {
        @Html.Partial("~/YourPath/RenderElement.cshtml", node)
    }
</ul>

Render element in a view :

@model YourRecursiveNode
<li>
    <a href="@Model.Href">
        <span>@Model.Display</span>
    </a>
    @Html.Partial("~/YourPath/RenderChildren.cshtml", Model)
</li>

Then loop node's children in another view:

@model YourRecursiveNode
@if (Model.HasChildren)
{
    <ul>
        @foreach (var child in Model.Children)
        {
            @Html.Partial("~/YourPath/RenderElement.cshtml", child)
        }
    </ul>
}

Upvotes: 2

Matt DeKrey
Matt DeKrey

Reputation: 11932

Referring to a few design discussions that we only have glimpses of online, @helper was removed for design reasons; the replacement is View Components.

I'd recommend a View Component that looked like the following:

public class ConfigurationKeysViewComponent : ViewComponent
{
    private readonly IConfiguration config;
    public ConfigurationKeysViewComponent(IConfiguration config)
    {
        this.config = config;
    }

    public IViewComponentResult Invoke(string currentSubKey = "")
    {
        return View(new ConfigurationData
        {
            Key = currentSubKey,
            Value = config.Get(currentSubKey),
            SubKeys = config.GetSubKey(currentSubKey).GetSubKeys().Select(sk => sk.Key)
        });
    }
}

Your ViewComponent's View would then be relatively simple:

<dt>@Model.Key</dt>
<dd>@config.Get(Model.Key)</dd>
@foreach (var sk in Model.SubKeys)
{
    @Component.Invoke("ConfigurationKeys", sk)
}

You could then invoke it from your root view as follows:

@Component.Invoke("ConfigurationKeys")

Disclaimer: I wrote this in the SO editor, there may be compiler errors. Also, I'm uncertain if View Components support default parameters - you may need to add a default "" to the root view's call to the view component.

Alternatively, if this is just debugging code, you can unwrap your recursiveness by using a Stack<>.

Upvotes: 1

Related Questions