0

When I surf to the address like this:

server:port/Controller

it automatically assumes that the action requested is Index, so the displayed page is equivalent to this:

server:port/Controller/Index

My problem is that when I execute something like this on a button click:

$(function () {
  $("#clickaroo").click(function (event) {
    event.preventDefault();
    $.post("Action", null, function () { ... });
  });
});

it fails when I'm at Index implicitly (i.e. page for that action is shown but the URL doesn't contain its name), while working when accessing it explicitly (i.e. URL says .../Controller/Index). If I then change the post into this:

$.post("Controller/Action", null, function () { ... });

it works for the former but starts to fail for the latter. Of course, I do understand why - location.href is suffixed by /Action and without the controller's name or with the name repeated, it gets confused. What's a best-practice way to handle that?

  • Horse around with RouteConfig.cs file? (sounds overkill)
  • Adding a condition in the JS? (feels as a baaad design)
  • Force the URL to be explicitly suffixed? (unsure how to)
Konrad Viltersten
  • 36,151
  • 76
  • 250
  • 438
  • Take a look at this http://stackoverflow.com/questions/34360537/how-do-i-make-js-know-about-the-application-root – Shyju Jan 19 '16 at 18:53

2 Answers2

1

The best solution is to use the Url.Action or Url.RouteUrl html helper method(s) to build the correct relative url to the action method. This will take care of building the correct url irrespective of the current page/view you are in.

var url1="@Url.Action("Create","Home")";
//use url1 now.

The above code will work if you have your javascript inside the razor views. If your script is inside an external file, You can build the relative url to the root and pass that to your js file and use that to build the url's as needed. Make sure to use javascript namespacing when doing so to avoid possible issues with global javascript variables.

So in your razor view (Layout file or specific view), you may do this.

<script>
    var myApp = myApp || {};  
    myApp.Urls = myApp.Urls || {};
    myApp.Urls.baseUrl = '@Url.Content("~")';
    myApp.Urls.jobListUrl= '@Url.Action("Index","jobs")';
</script>
<script src="~/Scripts/YourExternalJsFile.js"></script>

And in your YourExternalJsFile.js file, you can read it like

var urlToJobIndex= myApp.Urls.jobListUrl;
// Or With the base url, you may safely add the remaining url route.
var createUrl= myApp.Urls.baseUrl+"home/create";

Edit : If you simply care about getting the root/base url of the site so you can append that to get the other url you are after, you may simply use / as the first character of your url.

   var createUrl= "/home/create";

For your specific click event on an anchor tag use case, you can simply read the href attribute value of your link and use that.

If you want to make the ajax call to the same action method as the href attribute value of the link.

<a id="clickaroo" href="@Url.Action("Create","Customer")">Create<a/>

And in your click event get the href attribute value

$(function(){

  $("#clickaroo").click(function(e){
    e.preventDefault();
    var u = $(this).attr("href");
    $.post(u,function(response){

    });
  });

});

If you want to make the ajax call to the some other action method than the one in href attribute value of the link.

Here you can use data attribute to keep the other url in the link tag markup.

<a id="clickaroo" href="#" data-targurl="@Url.Action("Create","Customer")">Create<a/>

And in your click event get the data attribute value for "targurl" $(function(){

  $("#clickaroo").click(function(e){
    e.preventDefault();
    var u = $(this).data("targurl");
    $.post(u,function(response){

    });
  });

});
Shyju
  • 214,206
  • 104
  • 411
  • 497
1

You can use html5 attirbute as you have extetnal js files so razor will not be accessible there, use data- attribute on your button and then pick the url via jquery in the click handle like:

<button  id="clickaroo" data-url="@Url.Action("Action","Controller")">Click me</button>

and then in js file:

$("#clickaroo").click(function (event) {
    event.preventDefault();
    var button = $(this);
    $.post(button.data("url"), null, function () { ... });
  });
Ehsan Sajjad
  • 61,834
  • 16
  • 105
  • 160
  • This was new to me. Does it mean that I can add any attribute to any, e.g. ** and then in my JS access it like *$.post(img.donkey("shazoo"), ...*? Or is that toy only for buttons? Only for data? Only for url? – Konrad Viltersten Jan 19 '16 at 18:53
  • i have not tried that but, you should be using html5 data- attribute, `data-shazoo` or `data-donkey`, not sure about `donkey-shazoo` you can try it in a jsfiddle to see if that works – Ehsan Sajjad Jan 19 '16 at 18:58
  • I see. The *data* part being **the** word. Didn't know about it, hence the question. Even if it'd work, I prefer not to confuse others with my code so I'll play nice and keep to *data-shazoo*'s, hehe. – Konrad Viltersten Jan 19 '16 at 19:00