4

I have this ActionLink.

@Html.ActionLink("Link", "action", "controller", null, htmlAttributes: new {@class = "menuLink"})

I have to set routeValues to null because I don't know the value at compiletime. They are recieved from the selectedvalue of some dropdowns at runtime.

Hence, I am trying to augment the routevalues at runtime with JavaScript. I can't see what other choise I have.

I use the CSS class menuLink on the ActionLink to catch the event.

$(".menuLink").click(function () {
    var $self = $(this),
        routeValue1 = getFromDropdown1(),
        routeValue2 = getFromDropdown2(),
        href = $self.attr("href");

     // ???
});

How can I add the routevalues to make the href correct?

I want the URL to be something like this:

http://localhost/mySite/controller/action/2/2

My focus is on the /2/2 part..

I have tryed this

$self.attr("foo", routeValue1);
$self.attr("bar", routeValue2);

But then I get a URL like this:

http://localhost/mySite/controller/action?foo=2&bar=2

And it doesn't work with my routes.MapeRoute

routes.MapRoute(
    name: "Authenticated",
    url: "{controller}/{action}/{foo}/{bar}",
    defaults: new { controller = "Home", action = "WelcomePage", Foo = "0", Bar = "0" }
);

I don't know if Foo = "0", Bar = "0" is the problem.

Solution added. Thanks to @Zabavsky

if (!String.format) {
    String.format = function (format) {
        var args = Array.prototype.slice.call(arguments, 1);
        return format.replace(/{(\d+)}/g, function (match, number) {
            return typeof args[number] != 'undefined'
                ? args[number]
                : match
            ;
        });
    };
}

var href = $self.attr("href");
var hrefDecoded = decodeURIComponent(href);
var hrefFormatted = String.format(hrefDecoded, 2, 1); // 2 and 1 test only..
$self.attr('href', hrefFormatted);
radbyx
  • 9,352
  • 21
  • 84
  • 127

2 Answers2

3

I'm not sure this is the best way of doing this, but I'll provide you with my solution to this problem. The main idea is to generate the link with all required parameters and format the href with javascript, like string.Format in c#.

  1. Generate the link:
@Html.ActionLink("Link", "action", "controller",
    new { Foo = "{0}", Bar = "{1}"}, htmlAttributes: new { @class = "menuLink" })

The helper will generate the correct url, which according to your route configuration will look like this:

<a href="http://website.com/controller/action/{0}/{1}" class="menuLink">Link</a>
  1. Write the format function.

You can check how to implement one here. If you are using jQuery validation plugin you can utilize the built in format function.

  1. Format href attribute in your javascript:
$(".menuLink").click(function () {
    var routeValue1 = getFromDropdown1(),
        routeValue2 = getFromDropdown2(),
        url = decodeURIComponent(this.href);

    // {0} and {1} will be replaced with routeValue1 and routeValue1
    this.href = url.format(routeValue1, routeValue2);
});

Do not concatenate route parameters to the href like this href +'/'+ routeValue1 +'/'+routeValue2, the url will result in 404 if you change your route configuration. You should always generate urls with Url helpers and avoid hadcoding them in the javascript code.

Community
  • 1
  • 1
Zabavsky
  • 13,340
  • 8
  • 54
  • 79
  • That's what I am trying to accomplish. Use helpers the right way and have a less javascript in use as possible. I like your solution where you really take advanges of the format method. – radbyx Jun 17 '15 at 13:00
  • Do I need to augment the String.prototype with the method format first for this to work, like this? Do you have that already? http://stackoverflow.com/questions/610406/javascript-equivalent-to-printf-string-format – radbyx Jun 17 '15 at 13:10
  • You can implement it in any way you want, I just gave you the idea. – Zabavsky Jun 17 '15 at 13:13
  • I just want to understand if I have `format` already or need to do something about it. – radbyx Jun 17 '15 at 13:17
  • I don't think you have format already, unless you are using jQuery validation. You have to implement it based on the samples I gave or those you found by yourself, which is pretty straightforward. – Zabavsky Jun 17 '15 at 13:19
  • I can't make it work, do you mind helping me more? alert('href before: ' + $self.attr("href")); Gives: "href before: /mysite/controller/action/%7B0%7D/%7B1%7D". Also what format method do you reccommend? I tryed both but it doesn't work. Maybe because my href has "%7B0%7D/%7B1%7D" and not "{0}/{1}".. How do I fix that? Thanks. – radbyx Jun 17 '15 at 13:33
  • 1
    @radbyx, yes, I forgot that you have to decode the `href` before formatting it using `decodeURIComponent` function. Check my edit. – Zabavsky Jun 17 '15 at 13:43
  • Yes you have, it's a javascript function. – Zabavsky Jun 17 '15 at 13:45
  • Thanks that decode worked. Now I have the error "format is not a function" problem even though tryed to add if (!String.format) { String.format = function(format) { var args = Array.prototype.slice.call(arguments, 1); return format.replace(/{(\d+)}/g, function(match, number) { return typeof args[number] != 'undefined' ? args[number] : match ; }); }; } just before i used it. But at least im getting closer. I never tryed to augment String or something before.. just read about it could be done, if you are missing some handy JS function. :) – radbyx Jun 17 '15 at 13:51
  • So finally got it. Big thanks man. I have added the solution for others. – radbyx Jun 17 '15 at 15:12
1

You can change the href attribute of anchor tag dynamically like below.

$(".menuLink").click(function () {
    var $self = $(this),
        routeValue1 = getFromDropdown1(),
        routeValue2 = getFromDropdown2(),
        href = $self.attr("href"),
        editedHref = href.split('?')[0];

    $self.attr('href', editedHref+'/'+ routeValue1  +'/'+routeValue2 );
});
radbyx
  • 9,352
  • 21
  • 84
  • 127
Nitin Varpe
  • 10,450
  • 6
  • 36
  • 60