In my ASP.net web project, I've written the following Javascript code in a .js file:
function getDeviceTypes() {
var deviceTypes;
$.ajax({
async: false,
type: "POST",
url: "Controls/ModelSelectorWebMethods.aspx/getDeviceTypes",
data: '{ }',
contentType: "application/json;",
dataType: "json",
success: function(response) {
deviceTypes = response.d;
},
error: function(xhr, status) {
debugger;
alert('Error getting device types.');
}
}); // end - $.ajax
return deviceTypes;
}
It was working great until I tried to load this .js file into a page in a subdirectory.
Let's suppose that the name of my project is widget.
When I use this code in the main virtual directory, Javascript interprets Controls/ModelSelectorWebMethods.aspx/getDeviceTypes to mean https://mysite.com/widget/Controls/ModelSelectorWebMethods.aspx/getDeviceTypes and all is well. However, from the page in a subdirectory, Javascript interprets it to mean https://mysite.com/widget/subdirectory/Controls/ModelSelectorWebMethods.aspx/getDeviceTypes and it doesn't work.
How can I write my Javascript code so that the AJAX web method can be called from pages in any directory in my application?
You've got two options:
Build a configuration/ preferences object in JavaScript which contains all your environment specific settings:
var config = {
base: <% /* however the hell you output stuff in ASPX */ %>,
someOtherPref: 4
};
and then prefix the AJAX url with config.base (and change the value for config.base whether you're on a dev/ testing/ deployment server.)
Use the <base /> HTML tag to set the URL prefix for all relative URL's. This affects all relative URL's: image's, links etc.
Personally, I'd go for option 1. You'll most likely find that config object coming in handy elsewhere.
Obviously the config object will have to be included in a part of your site where server-side-code is evaluated; a .js file won't cut it without configuring your server. I always include the config object in the HTML <head>; its a small config object, whose contents can change on each page, so it's perfectly warrented to stick it in there.
As long as you don't care about asp.net virtual directories (which makes it actually impossible to figure out from script, you'll have to pass something from the server) you can look at the URL and parse it:
function baseUrl() {
var href = window.location.href.split('/');
return href[0]+'//'+href[2]+'/';
}
then:
...
url: baseUrl()+"Controls/ModelSelectorWebMethods.aspx/getDeviceTypes",
...
... and now I see from your comments above that virtual directories are a problem. I usually do this.
1) In your masterpage, put code to inject a script somewhere, preferably before anything else (I add it directly to HEAD by adding controls instead of using ScriptManager) to make sure it's run before any other script. c#:
string basePath = Request.ApplicationPath;
// Annoyingly, Request.ApplicationPath is inconsistent about trailing slash
// (if not root path, then there is no trailing slash) so add one to ensure
// consistency if needed
string myLocation = "basePath='" + basePath + basePath=="/"?"":"/" + "';";
// now emit myLocation as script however you want, ideally in head
2) Change baseUrl to include that:
function baseUrl() {
var href = window.location.href.split('/');
return href[0]+'//'+href[2]+basePath;
}
Create an app root variable...
var root = location.protocol + "//" + location.host;
And use an absolute URI (instead of relative) when you are making AJAX requests...
url: root + "/Controls/ModelSelectorWebMethods.aspx/getDeviceTypes"
I think this function will work... it is to get a relative path as "../../../"
so if you invoke this function in each page, this will return a relative path format.
function getPath() {
var path = "";
nodes = window.location. pathname. split('/');
for (var index = 0; index < nodes.length - 3; index++) {
path += "../";
}
return path;
}
You can import the namespace at the beginning: System.Web.Hosting.HostingEnvironment
<%# Master Language="VB" AutoEventWireup="false" CodeFile="Site.master.vb" Inherits="Site" %>
<%# Import namespace="System.Web.Hosting.HostingEnvironment" %>
and on js:
<script type="text/javascript">
var virtualpathh = "<%=ApplicationVirtualPath %>";
</script>
Could you use window.location.pathname?
var pathname = window.location.pathname;
$.ajax({
//...
url: pathname + 'Controls/...', // might need a leading '/'
//...
});
Related
This is the url which i am trying to hit from within .js file which contains knockout related function:
self.followAction = $.resolvePath("/People/Follow?uid=" + data.UserId);
here People is the controller and Follow is the action method, on button click, i want to send userId along so i have written this.
To resolve relative path from within javascript, i have written this function
// Fix for resolving relative paths from within js scripts
$.resolvePath = function(url)
{
var path = '#Request.ApplicationPath';
if (path != '/') return path + url;
return url;
};
But, on button click, i am getting this error: HTTP Error 404.0 - Not Found
and url is:
localhost:44305/People/#Request.ApplicationPath/People/Follow?uid=8
please tell me what should i try now. thnks in advance!
Razor code is not interpreted within JS files, hence the #Request.ApplicationPath is read as a literal string. You need to put that code somewhere where it will be executed so that your JS can read it; perhaps as a data-* attribute on an element in your View, something like this:
<!-- in a layout view... -->
<body data-app-path="#Request.ApplicationPath">
$.resolvePath = function(url) {
var path = $('body').data('app-path');
if (path != '/')
return path + url;
return url;
};
I am building a web app in which I have a number of clickable maps, stored as static SVG files, that I would like to be able to swap dynamically based on a menu-click. So far, I have javascript code to call my Catalyst controller, and I would like it to return the contents of the SVG file in the response body. So far I can get the javascript to catch the menu clicks and call the controller, and in the controller I am able to get the name of the file out of my database. I am stuck at that step, though, and have been thus far unable to find out how to read the contents of that file in the controller and return it to the javascript controller. Any help would be appreciated!
UPDATE:
The (Edited) code below works, but I'm not sure if this is the best way. I would definitely be open to suggestions on ways to improve my process. Thanks!
Javascript:
$(document).on("click",".map_select", function(e){
$(document.getElementById("som_map")).load("[% c.uri_for('/maps/update_map/') %]" + this.title);
})
HTML
<svg id="som_map" class="mapmain" width="720px" height="430px">
</svg>
PERL
sub update_map :Path :Local :Args(1) {
my ( $self, $c, $map_id ) = #_;
my $fields = $c->model('DB::Map')->find($map_id);
my $map_file = $fields->get_column('map_file');
my $svg;
my $path = "root/static/svg/$map_file";
open my $fh, '<', $path;
{
local $/ = undef;
$svg = <$fh>;
}
close $fh;
$c->res->body($svg);
}
SVG files are stored in root/static/svg/
Unless you have a reason to do it, I would use your web server (Apache, nginx, ...) serve the file for you instead of handling the file I/O inside of your controller.
In your load function in javascript pass in a function that returns a URL for you:
$(document.getElementById("som_map")).load(getSVGUrl(this.title));
Then define that function to call Catalyst to get the appropriate URL for the given mapId:
function getUrl(mapId) {
var returnUrl;
jQuery.ajax({
url: "[% c.uri_for('/maps/update_map/') %]"
+ mapId,
success: function(result) {
if(result.isOk == false)
returnUrl = result.message;
},
async: false,
dataType: 'text/plain'
});
return returnUrl;
}
This function should call your application and just expect to get the URL back. It should be fast enough that making it synchronous does not matter.
Finally, your Catalyst function should just return the URL to the document:
sub update_map :Path :Local :Args(1) {
my ( $self, $c, $map_id ) = #_;
my $fields = $c->model('DB::Map')->find($map_id);
my $map_file = $fields->get_column('map_file');
$c->res->body("<appropriate URL path to document>/$map_file");
}
This will get your application out of the document handling business, trim down your controller, and allow your web server to do what it does best - serve documents.
I have an ASP.NET MVC3 application published to a url like this:
http://servername.com/Applications/ApplicationName/
In my code, I am using jquery ajax requests like this:
$.get(('a/b/c'), function (data) {}, "json");
When I run the application locally, the ajax request goes directly to the correct page (being an mvc route) because the local page ends with a "/" (localhost/a/b/c).
However, when I publish to http://servername.com/Applications/ApplicationName/, the trailing "/" is not always present. The url could be http://servername.com/Applications/ApplicationName, which then causes the ajax request to try to load http://servername.com/Applications/ApplicationNamea/b/c, which fails for obvious reasons.
I have already looked into rewriting the url to append a trailing slash, but A) It didn't work, and B) I feel like it's a poor solution to the problem, and that it would be better to configure the javascript urls to work properly regardless of the local folder setup.
I did try "../a/b/c" and "/a/b/c", but neither seemed to work.
Thanks in advance for the help!
Personally I tend to use a global variable of the relative URL of the server in my view like:
var BASE_URL = '#Url.Content("~/")';
Then you can do things like :
$.get(BASE_URL + 'a/b/c'), function (data) {}, "json");
I would like to add that if you want it to be totally global, you could add it to your /Views/Shared/_Layout.cshtml instead.
I ran into the same problem, and ended up creating two JavaScript functions that mirror the functionality of the MVC Url helper methods Url.Action and Url.Content. The functions are defined in the _Layout.cshtml file, so are available on all views, and work regardless of whether the application is in the root of the localhost or in a subfolder of a server.
<script type="text/javascript">
function UrlAction(action, controller) {
var url = ('#Url.Action("--Action--","--Controller--")').replace("--Action--", action).replace("--Controller--", controller);
return url;
}
function UrlContent(url) {
var path = "#Url.Content("~/--file--")";
path = path.replace("--file--", url.replace('~/', ''));
return path;
}
</script>
These can then be called like so:
var url = UrlAction('AvailableAssetClasses', 'Assessment');
var url2 = UrlContent('~/Images/calendar.gif');
Always use Url helpers when generating urls in an ASP.NET MVC application and never hardcode them. So if this script is directly inside the view:
<script type="text/javascript">
var url = '#Url.Action("a", "b")';
$.get(url, function (data) {}, "json");
</script>
And if this script is inside a separate javascript file (as it should be) where you don't have access to server side helpers, you could simply put the url in some related DOM element. For example using HTML5 data-* attributes:
<div data-url="#Url.Action("a", "b")" id="foo">Click me</div>
and then in your javascript file:
$('#foo').click(function() {
var url = $(this).data('url');
$.get(url, function (data) {}, "json");
});
and if you are unobtrusively AJAXifying an anchor or a form, well, you already have the url:
$('a#someAnchor').click(function() {
var url = this.href;
$.get(url, function (data) {}, "json");
return false;
});
I use Underscore template. It is possible to attach a external file as template?
In Backbone View I have:
textTemplate: _.template( $('#practice-text-template').html() ),
initialize: function(){
this.words = new WordList;
this.index = 0;
this.render();
},
In my html is:
<script id="practice-text-template" type="text/template">
<h3>something code</h3>
</script>
It works well. But I need external template.
I try:
<script id="practice-text-template" type="text/template" src="templates/tmp.js">
or
textTemplate: _.template( $('#practice-text-template').load('templates/tmp.js') ),
or
$('#practice-text-template').load('templates/tmp.js', function(data){ this.textTemplate = _.template( data ) })
but it did not work.
Here is a simple solution:
var rendered_html = render('mytemplate', {});
function render(tmpl_name, tmpl_data) {
if ( !render.tmpl_cache ) {
render.tmpl_cache = {};
}
if ( ! render.tmpl_cache[tmpl_name] ) {
var tmpl_dir = '/static/templates';
var tmpl_url = tmpl_dir + '/' + tmpl_name + '.html';
var tmpl_string;
$.ajax({
url: tmpl_url,
method: 'GET',
dataType: 'html', //** Must add
async: false,
success: function(data) {
tmpl_string = data;
}
});
render.tmpl_cache[tmpl_name] = _.template(tmpl_string);
}
return render.tmpl_cache[tmpl_name](tmpl_data);
}
Using "async: false" here is not a bad way because in any case you must wait until template will be loaded.
So, "render" function
allows you to store each template in separate html file in static
dir
is very lightweight
compiles and caches templates
abstracts template loading logic. For example, in future you can use preloaded and precompiled templates.
is easy to use
[I am editing the answer instead of leaving a comment because I believe this to be important.]
if templates are not showing up in native app, and you see HIERARCHY_REQUEST_ERROR: DOM Exception 3, look at answer by Dave Robinson to What exactly can cause an "HIERARCHY_REQUEST_ERR: DOM Exception 3"-Error?.
Basically, you must add
dataType: 'html'
to the $.ajax request.
EDIT: This answer is old and outdated. I'd delete it, but it is the "accepted" answer. I'll inject my opinion instead.
I wouldn't advocate doing this anymore. Instead, I would separate all templates into individual HTML files. Some would suggest loading these asynchronously (Require.js or a template cache of sorts). That works well on small projects but on large projects with lots of templates, you find yourself making a ton of small async requests on page load which I really dislike. (ugh... ok, you can get around it with Require.js by pre-compiling your initial dependencies with r.js, but for templates, this still feels wrong to me)
I like using a grunt task (grunt-contrib-jst) to compile all of the HTML templates into a single templates.js file and include that. You get the best of all worlds IMO... templates live in a file, compilation of said templates happen at build time (not runtime), and you don't have one hundred tiny async requests when the page starts up.
Everything below is junk
For me, I prefer the simplicity of including a JS file with my template. So, I might create a file called view_template.js which includes the template as a variable:
app.templates.view = " \
<h3>something code</h3> \
";
Then, it is as simple as including the script file like a normal one and then using it in your view:
template: _.template(app.templates.view)
Taking it a step further, I actually use coffeescript, so my code actually looks more like this and avoid the end-of-line escape characters:
app.templates.view = '''
<h3>something code</h3>
'''
Using this approach avoids brining in require.js where it really isn't necessary.
This mixin allows you to render external template using Underscore in very simple way: _.templateFromUrl(url, [data], [settings]). Method API is almost the same as Underscore's _.template(). Caching included.
_.mixin({templateFromUrl: function (url, data, settings) {
var templateHtml = "";
this.cache = this.cache || {};
if (this.cache[url]) {
templateHtml = this.cache[url];
} else {
$.ajax({
url: url,
method: "GET",
async: false,
success: function(data) {
templateHtml = data;
}
});
this.cache[url] = templateHtml;
}
return _.template(templateHtml, data, settings);
}});
Usage:
var someHtml = _.templateFromUrl("http://example.com/template.html", {"var": "value"});
I didn't want to use require.js for this simple task, so I used modified koorchik's solution.
function require_template(templateName, cb) {
var template = $('#template_' + templateName);
if (template.length === 0) {
var tmpl_dir = './templates';
var tmpl_url = tmpl_dir + '/' + templateName + '.tmpl';
var tmpl_string = '';
$.ajax({
url: tmpl_url,
method: 'GET',
contentType: 'text',
complete: function (data, text) {
tmpl_string = data.responseText;
$('head').append('<script id="template_' + templateName + '" type="text/template">' + tmpl_string + '<\/script>');
if (typeof cb === 'function')
cb('tmpl_added');
}
});
} else {
callback('tmpl_already_exists');
}
}
require_template('a', function(resp) {
if (resp == 'tmpl_added' || 'tmpl_already_exists') {
// init your template 'a' rendering
}
});
require_template('b', function(resp) {
if (resp == 'tmpl_added' || 'tmpl_already_exists') {
// init your template 'b' rendering
}
});
Why to append templates to document, rather than storing them in javascript object? Because in production version I would like to generate html file with all templates already included, so I won't need to make any additional ajax requests. And in the same time I won't need to make any refactoring in my code, as I use
this.template = _.template($('#template_name').html());
in my Backbone views.
This might be slightly off topic, but you could use Grunt (http://gruntjs.com/) - which runs on node.js (http://nodejs.org/, available for all major platforms) to run tasks from the command line. There are a bunch of plugins for this tool, like a template compiler, https://npmjs.org/package/grunt-contrib-jst. See documentation on GitHub, https://github.com/gruntjs/grunt-contrib-jst. (You will also need to understand how to run node package manager, https://npmjs.org/. Don't worry, it's incredibly easy and versatile. )
You can then keep all your templates in separate html files, run the tool to precompile them all using underscore (which I believe is a dependency for the JST plugin, but don't worry, node package manager will auto install dependencies for you).
This compiles all your templates to one script, say
templates.js
Loading the script will set a global - "JST" by default - which is an array of functions, and can be accessed like so:
JST['templates/listView.html']()
which would be similar to
_.template( $('#selector-to-your-script-template'))
if you put the content of that script tag in (templates/)listView.html
However, the real kicker is this: Grunt comes with this task called 'watch', which will basically monitor changes to files that you have defined in your local grunt.js file (which is basically a config file for your Grunt project, in javascript). If you have grunt start this task for you, by typing:
grunt watch
from the command line, Grunt will monitor all changes you make to the files and auto-execute all tasks that you have setup for it in that grunt.js file if it detects changes - like the jst task described above. Edit and then save your files, and all your templates recompile into one js file, even if they are spread out over a number of directories and subdirectories.
Similar tasks can be configured for linting your javascript, running tests, concatenating and minifying / uglifying your script files. And all can be tied to the watch task so changes to your files will automatically trigger a new 'build' of your project.
It takes some time to set things up and understand how to configure the grunt.js file, but it well, well worth the time invested, and I don't think you will ever go back to a pre-grunt way of working
I think this is what might help you. Everything in the solution revolves around require.js library which is a JavaScript file and module loader.
The tutorial at the link above shows very nicely how a backbone project could be organized. A sample implementation is also provided. Hope this helps.
I got interested on javascript templating and now I'm taking the first steps with backbone. This is what i came up with and seems to work pretty well.
window.App = {
get : function(url) {
var data = "<h1> failed to load url : " + url + "</h1>";
$.ajax({
async: false,
url: url,
success: function(response) {
data = response;
}
});
return data;
}
}
App.ChromeView = Backbone.View.extend({
template: _.template( App.get("tpl/chrome.html") ),
render: function () {
$(this.el).html(this.template());
return this;
},
});
App.chromeView = new App.ChromeView({ el : document.body });
App.chromeView.render();
I had to set the data type to "text" to make it work for me:
get : function(url) {
var data = "<h1> failed to load url : " + url + "</h1>";
$.ajax({
async: false,
dataType: "text",
url: url,
success: function(response) {
data = response;
}
});
return data;
}
I found a solution that works for me with using jQuery.
I add the underscore template code, with jQuery.load() method, to the main html file.
Once it's there, I'm using it for generating the templates.
All need to happen synchronously!
The concept is:
I have a underscore map template code:
<!-- MAP TEMPLATE-->
<script type="text/template" id="game-map-template">
<% _.each(rc, function(rowItem, index){ %>
<ul class="map-row" data-row="<%- index %>">
<li class="map-col <%- colItem.areaType ? 'active-area' : '' %>"></li>
...
</script>
And I put that code in a file called map-template.html
After that I create a a wrapper for the template files.
<div id="templatesPool"></div>
Then I include that file in my main html file like so.
In head:
<!-- Template Loader -->
<script>
$(function(){
$("#templatesPool").append($('<div>').load("map-template.html"));
});
</script>
Cheers.
I know this question is really old but it came up as the first result on a google search for underscore ajax templates.
I was tired of not finding a good solution for this so I created my own:
https://github.com/ziad-saab/underscore-async-templates
In addition to loading underscore templates using AJAX, it adds <% include %> functionality. I hope it can be useful to someone.
I was a bit uneasy forcing jQuery to function synchronously, so I modified the previous synchronous example using promises. It's pretty much the same, but runs asynchronously. I'm using hbs templates in this example:
var asyncRenderHbs= function(template_name, template_data) {
if (!asyncRenderHbs.template_cache) {
asyncRenderHbs.template_cache= {};
}
var promise= undefined;
if (!asyncRenderHbs.template_cache[template_name]) {
promise= new Promise(function(resolve, reject) {
var template_url= '/templates/' + template_name;
$.ajax({
url: template_url,
method: 'GET',
success: function(data) {
asyncRenderHbs.template_cache[template_name]= Handlebars.compile(data);
resolve(asyncRenderHbs.template_cache[template_name](template_data));
},
error: function(err, message) {
reject(err);
}
});
});
} else {
promise= Promise.resolve(asyncRenderHbs.template_cache[template_name](template_data));
}
return promise;
};
Then to use the rendered html:
asyncRenderHbs('some_template.hbs', context)
.then(function(html) {
applicationMain.append(html);
// Do other stuff here after html is rendered...
})
.catch(function(err) {
// Handle errors
});
NOTE: As discussed by others, it would be preferable to compile all templates into a single templates.js file and load that in the beginning rather than have many small synchronous AJAX calls to get templates when the webpage loads.
Forward warning - Here be dragons:
I mention the approach shown below simply to help those struggling to make ASP.NET stacks (and similar frameworks) work harmoniously with the ecosystem of js-libs. It goes without saying that this is not a generic solution. Having said that ...
/endforwardwarning
If you are using ASP.NET you can externalize your templates simply by placing them inside one or more partial views of their own. Aka inside your .cshtml:
#Html.Partial("path/to/template")
Inside your template.cshtml:
// this is razorview and thusly if you ever need to use the # character in here
// you will have to either escape it as ## or use the html codepoint which is @
// http://stackoverflow.com/questions/3626250/escape-character-in-razor-view-engine
<script type="text/x-template" id="someId">
<span class="foo"><%= name %></span>
</script>
And now you can use the template like usual:
_.template($("#someId").html())({ name: "Foobar" });
Hope this elusively-obvious approach helps someone save an hour's worth of head-scratching.
Any smart way of doing a "root" based path referencing in JavaScript, just the way we have ~/ in ASP.NET?
Have your page generate a tag with something like:
<link rel="home" id="ApplicationRoot" href="http://www.example.com/appRoot/" />
Then, have a function in JavaScript that extracts the value such as:
function getHome(){
return document.getElementById("ApplicationRoot").href;
}
Use base tag:
<head>
<base href="http://www.example.com/myapp/" />
</head>
...
from now any link use on this page, no matter in javascript or html, will be relative to the base tag, which is "http://www.example.com/myapp/".
You could also use the asp.net feature VirtualPathUtility:
<script>
var basePath = '<%=VirtualPathUtility.ToAbsolutePath("~/")%>';
</script>
Notice: I don't encode the path to a JSON-string (escape quotes, control characters etc). I don't think this is a big deal (quotes for example aren't allowed unescaped in an URL), but one never knows...
I usually create a variable at the top of the js file and assign it the root path. Then I use that variable when referencing a file.
var rootPath = "/";
image.src = rootPath + "images/something.png";
~/ is the application root and not a literal root, it interpets ~/ to mean <YourAppVirtualDir>/
To do a literal root in JavaScript it's just /, i.e "/root.html". There's no way of getting an application level path like that in JavaScript.
You could hack it in the ASPX file and output it in a tag but I would consider the security implications of that.
Kamarey's answer can be improved to support a dynamic base path:
<head>
<base href="http://<%= Request.Url.Authority + Request.ApplicationPath%>/" />
</head>
This will ensure a correct root path regardless of deployment configuration.
To be fair, this doesn't answer the original question, but it elimiates most needs for getting the root path from javascript. Simply use relative URL's everywhere, without prefixing with slash.
Should you still need to access it from javascript, add an id attribute and use document.getElementFromId() as MiffTheFox suggested - but on the base-tag.
Another option that's a bit simpler and more universal would be to take the following:
<script src="/assets/js/bootstrap.min.js"><script>
and use Page.ResolveClientUrl like so:
<script src='<%=ResolveClientUrl("~/assets/js/bootstrap.min.js")%>'></script>
then regardless of what subdirectory the urls will always be rendered correctly.
The following function will calculate the root of the currently running application. I use it to locate the absolute location of resources, when called from somewhere deep within the application tree.
function AppRoot() {
//
// Returns the root of the currently running ASP application.
// in the form: "http://localhost/TRMS40/"
//
// origin: "http://localhost"
// pathname: "/TRMS40/Test/Test%20EMA.aspx"
//
// usage:
// window.open( AppRoot() + "CertPlan_Editor.aspx?ID=" + ID);
//
var z = window.location.pathname.split('/');
return window.location.origin + "/" + z[1] + "/";
}
In the PreRender of your .NET base page, add this:
protected override void
OnPreRender(EventArgs e) {
base.OnPreRender(e);
if (Page.Header != null)
{
//USED TO RESOLVE URL IN JAVASCRIPT
string baseUrl = String.Format("var baseUrl='{0}';\n",
HttpContext.Current.Request.ApplicationPath);
Page.Header.Controls.Add(new LiteralControl(String.Format(Consts.JS_TAG,
baseUrl)));
}
}
Then in your global JavaScript function, add the following:
function resolveUrl(url) {
if (url.indexOf("~/") == 0) {
url = baseUrl + url.substring(2);
}
return url; }
Now you can use it like this:
document.getElementById('someimage').src = resolveUrl('~/images/protest.jpg');
May be a little much for some projects, but works great for full fledged applications.
Solution for ASP.NET MVC applications
This works when using IIS and also IIS Express in VS.
Put this snippet before all scripts load, in order to have the root url variable "approot".
at your service in the scripts:
<script>
var approot = "#Url.Content("~")";
</script>
--> other scripts go here or somewhere later in the page.
Then use it in your script or page script.
Example:
var sound_root_path = approot + "sound/";
var img_root_path = approot + "img/";
the approot variable will be something either:
"/YourWebsiteName/" <-- IIS
or just:
"/" <-- IIS Express
For ASP.net MVC Razor pages, Create a base tag like below in the <Head> tag
<base href="http://#Request.Url.Authority#Request.ApplicationPath" />
and in all your relative javascript URLs, make sure to start without a slash(/) otherwise it will refer from the root.
For ex. create all your urls like
"riskInfo": { url: "Content/images/RiskInfo.png", id: "RI" },
or
$http.POST("Account/GetModelList", this, request, this.bindModelList);
If you want to use it in HTML Still you can use ~, see this
href = #Url.Content("~/controllername/actionName")
See the check box click event in my MVC Application
#Html.CheckBoxFor(m=>Model.IsChecked,
new {#onclick=#Url.Content("~/controller/action("+ #Model.Id + ", 1)"),
#title="Select To Renew" })