views:

32

answers:

3

So I have my first MVC2 site that I'm working on and naturally I'd like to throw some AJAX in there. The problem is, is that I don't know how to get the URL for the action when passing in a URL parameter. Let me explain. The examples I've seen so far show the developer passing in strings like '/MyController/MyAction'. That's great, except if your controllers are not in the root directory of your website (as is the case in my situation). I could always use relative URLs like 'MyAction' except if the URL contains parameters that doesn't work either. Consider http://example.com/myroot/MyController/MyAction vs http://example.com/myroot/MyController/MyAction/PageNumber/SomeOtherValue. Now the relative URL will be incorrect.

In the ASPX code, this is easy. I just write in <%= Url.Action("MyAction") %>. But how do I do this in my javascript file?

+1  A: 

This is part of the long-standing issue that including server-sided code in JavaScript files is not really possible :(. (Without serious hacks, that is.)

The best solution is to include the action URL inside your HTML file somewhere, then get that value from JavaScript. My suggestion would be something like this:

<!-- in your view file  -->
<form id="MyForm" action="<%: Url.Action("MyAction") %>"> ... </form>

<!-- or -->
<a id="MyLink" href="<%: Url.Action("MyAction") %>"> ... </a>

combined with

// In your .js file
$("#MyForm").submit(function ()
{
    $.post($(this).attr("action"), data, function (result) { /* ... */ });
    return false;
});

// or
$("#MyLink").click(function ()
{
    $.getJSON($(this).attr("href"), data, function (result) { /* ... */ });
    return false;
});

This feels semantically clear to me, and in some cases even creates degradable fallback behavior for when JavaScript is turned off.

Domenic
Yeah, I was trying to get IIS to interpret the js file as aspx files, but ran into a lot of problems. I like what you're suggesting above. I'll give it a try and see what happens.
Jason Thompson
Alright, this strategy works. I'm using hidden variables to do this, but it seems to do what I need. I wish there was a cleaner way, however, since now my javascript file is even more tightly coupled to my view. Perhaps that's not as big of a deal as I think it is. :)
Jason Thompson
@Jason I'm not suggesting Domenic's solution is wrong, in fact I use this approach frequently, but you might considering combining it with my solution below to eliminate the need for hidden elements which store script values. This approach is destined to fail if someone edits your code and haplessly deletes a seemingly-useless hidden element.
Nathan Taylor
Nathan, I see what you're saying and I appreciate the thought, however; for my purposes, it does not present me an advantage. From what I understand from your suggestion, I would simply have an initializer function rather than hidden variables. While I agree that this would look more important to another developer than hidden variables, I have marked off a section in my view just for this purpose. Also I'm the lead architect of the company I work for, so I simply need to train my team to leave the well marked hidden variables alone. Thanks again for the great suggestion.
Jason Thompson
@Jason No problem, good luck!
Nathan Taylor
Why not use the attributes? As I mentioned, semantically they make sense---even though the default behavior of clicking that link is not desirable, and you want to replace it with Ajax, `<a href="...">` still expresses "I am creating a link that should point to the `...` URI," independent of the desired behavior.
Domenic
A: 

Simple: tell your javascript what the correct URL is.

Tactically, you can get there alot of ways, but they basically break down into two techniques:

  • Have a server-side generated javascript "configuration" so you can do something like var url = siteConfiguration.SITEROOT + 'products/pink-bunny-slippers' Note this file can be a normal MVC view, the only trick is you have to tell the controller to send a text/javascript header rather than text/html.
  • Basically, dependency inject it into your script. IE function wireUpAjaxLinksToService(linkIdentifier, serviceEndpoint) where you call using something like wireUpAjaxLinks('a.ajax', '<%= Url.Action("MyService", "Services") %>')
Wyatt Barnett
+1  A: 

You can't do this in your JavaScript file directly, however you can pass these dynamic values into your script by way of a script initializer. Consider the following example:

External Js file

ShoppingCart = function() {
    this.settings = {
        AddProductToCartUrl: '',
        RemoveFromCartUrl: '',
        EmptyCartUrl: '',
        UpdateCartUrl: ''
    };
};

ShoppingCart.prototype.init = function(settings) {
    this.settings = jQuery.extend(this.settings, settings || {});
};

HTML/View

<script type="text/javascript">
    var cart = new ShoppingCart();
    cart.init({ AddProductToCartUrl: '<%=Url.Action("MyAction")%>' });

    alert(cart.settings.AddProductToCartUrl);
</script>
Nathan Taylor