0

I've been bashing my head for a quite some time now and I'm pretty sure I'm missing something very obvious. I want to create a route link, that can dynamically set css class to "selected", if the current controller action matches it. It's easy, however, I'm having troubles modifying existing htmlAttributes that I need to pass in.

public static MvcHtmlString RouteLinkSelectable(this HtmlHelper html, string linkText, string routeName, object routeValues, object htmlAttributes, string controller = null, string action = null)
{
        // omitting code for determining if the class should be set, because it
        // doesn't modify the behavior. It does that same thing with the following code

        var myAttributes = new Dictionary<string, object>
        {
            { "data-myattribute1", "value1" },
            { "data-myattribute2", "value2" }
        };

        var attributes = new RouteValueDictionary(htmlAttributes);
        // now merge them with the user attributes
        foreach (var item in attributes)
        {
            // remove this test if you want to overwrite existing keys
            if (!myAttributes.ContainsKey(item.Key))
            {
                myAttributes[item.Key] = item.Value;
            }
        }

        return html.RouteLink(linkText, routeName, routeValues, myAttributes);    
 }

This is the code (well one of the variations I've been trying) that was suggested by Darin Dimitrov in this answer https://stackoverflow.com/a/12729240/1289283

That should work, right? Well, not exactly..

When I call it from my layout like this:

@Html.RouteLinkSelectable("profil", "Default", null, new { id = "lnkProfile" }, action: "Index")  

It produces this output:

<a Comparer="System.Collections.Generic.GenericEqualityComparer`1[System.String]" Count="3" Keys="System.Collections.Generic.Dictionary`2+KeyCollection[System.String,System.Object]" Values="System.Collections.Generic.Dictionary`2+ValueCollection[System.String,System.Object]" href="/">profil</a>

If I modify the code to use classical syntax (...., new { id = "lnkProfile" }), it works good. If I create a new class with properties, it works good. If I use expando object, it doesn't attach any html properties... And if try to use a dictionary, the result is shown above... Please, can anyone explain it to me, why does it behave like this and how can I solve that?

Btw, of course I could create a link from scratch, but why reinvent the wheel when I simply need just to add one html attribute dynamically?

Community
  • 1
  • 1
walther
  • 13,466
  • 5
  • 41
  • 67

1 Answers1

1

The problem is that you are targeting the wrong overload of RouteLink, change the return statement with the following

return html.RouteLink(linkText, routeName, new RouteValueDictionary(routeValues), myAttributes);
  • Interesting, it seems to work, but why? I normally use that overload and when I specify it as "new { .... }", I don't have to change anything.. Seems very weird to me. Anyway, thanks for resolving it.. If you can further explain why it behaves differently, I'd be happy, but I'm marking this as an answer either way. – walther Dec 06 '14 at 15:16
  • either use an overload where routeValues is RouteValueDictionary and htmlAttributes is IDictionary or use the other overload where routeValues and htmlAttributes are both anonymous objects. In your first approach you were mixing them up. – Ibrahim ben Salah Dec 06 '14 at 23:00