user2668812
user2668812

Reputation: 427

MVC custom helper appending htmlAttributes

I have a custom helper class to highlight the selected menu item,

<li class="nav-item">
    @Html.MenuLink("Contact000", "Contact", "Home", new { @class = "nav-link" })
</li>   

I want to use the helper htmlattributes and append to CSS if selected condition is true. I have seen a Similiar question but was not able to find a question using

var attrs = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);

Here is my code

public static MvcHtmlString MenuLink(this HtmlHelper helper, string text, string action, string controller, object htmlAttributes)
{
    var routeData = helper.ViewContext.RouteData.Values;
    var currentController = routeData["controller"];
    var currentAction = routeData["action"];

    var attrs = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);

    if (String.Equals(action, currentAction as string,
        StringComparison.OrdinalIgnoreCase)
        &&
        String.Equals(controller, currentController as string,
        StringComparison.OrdinalIgnoreCase))
    {
        if (attrs.ContainsKey("class"))
        {
            attrs["class"] += " " + "currentMenuItem";
        }

        return helper.ActionLink(text, action, controller, attrs);
    }

    return helper.ActionLink(text, action, controller, htmlAttributes);
}

using

 var attrs = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);

I can append to the attributes.

when I return the helper.actionlink the attrs is not parsed correctly, below is the html generated,

<li class="nav-item">
    <a Count="1" Keys="System.Collections.Generic.Dictionary`2+KeyCollection[System.String,System.Object]" Values="System.Collections.Generic.Dictionary`2+ValueCollection[System.String,System.Object]" href="/Home/Contact?Length=4">Contact000</a>
</li>

I am trying to get the following,

<li class="nav-item">
    <a class="nav-link currentMenuItem" href="/Home/Contact">Contact000</a>
</li>

How do I convert attrs back into htmlAttributes for the helper to work ?

Upvotes: 3

Views: 2295

Answers (1)

budi
budi

Reputation: 6551

You can create a RouteValueDictionary using object htmlAttributes. Then you can append a value like you would with any other IDictionary<TKey, TValue> interface.

IDictionary<string, object> attrs = new RouteValueDictionary(htmlAttributes);

string key = "key";
string oldValue;
if (attrs.TryGetValue(key, out oldValue))
{
    // append to value
    attrs[key] = oldValue + "string to append";
}
else
{
    // key not in attrs, handle accordingly
}

Full example:

using System.Web.Routing;

public static MvcHtmlString MenuLink(this HtmlHelper helper,
    string text, string action, string controller, object htmlAttributes)
{
    var routeData = helper.ViewContext.RouteData.Values;
    var currentController = routeData["controller"];
    var currentAction = routeData["action"];

    IDictionary<string, object> attrs = new RouteValueDictionary(htmlAttributes);

    if (String.Equals(action, currentAction as string,
            StringComparison.OrdinalIgnoreCase)
        && String.Equals(controller, currentController as string,
                StringComparison.OrdinalIgnoreCase))
    {
        string clazz;
        if (attrs.TryGetValue("class", out clazz))
        {
            attrs["class"] = clazz + " " + "currentMenuItem";
        }
        // do you need to handle the case when there is no "class" attribute?

        return helper.ActionLink(text, action, controller, attrs);
    }

    return helper.ActionLink(text, action, controller, htmlAttributes);
}

EDIT: I found the actual issue to your problem, you are using the wrong Html.ActionLink overload.

You are currently using the ActionLink(HtmlHelper, String, String, Object, Object) overload, when you should be using the ActionLink(HtmlHelper, String, String, String, RouteValueDictionary, IDictionary<String, Object>) overload.

helper.ActionLink(text, action, controller, routeValues: null, htmlAttributes: attrs);

Upvotes: 2

Related Questions