What's the best way to avoid hardcoding URL's in JavaScript (primarily used when making AJAX calls)?
In the past:
Render JavaScript variable with result of #Url.Action or #Url.RouteUrl
Pass result of #Url.Action or #Url.RouteUrl to JavaScript in init/ctor.
Is there a better way?
It would be good to do something like this:
var url = $.routes("actionName", "controllerName") // or "routeName" for named routes
$.post(url, { id = 1 }, function() { //.. });
Which of course isn't really possible (JavaScript doesn't have direct access the to the ViewContext and thus doesn't have access to the route tables).
But i'm wondering if there's a way i can kind of setup my own "route table" for JavaScript, with only the ones i know it would need? (e.g i set it up in the View)
How do people handle this?
in-spite of injecting javascript in views i rather prefer - let HTML do its job and javascript do its. Below is the pattern.
For Links
/*A cssclass=ajaxlink is added to all those links which we want to ajaxify*/
//html in view
<a class='ajaxlink' href='#Url.Action("Action","Controller")'>I am An Ajax Link</a>
//generated clean html
<a class='ajaxlink' href='/controller/action'>I am An Ajax Link</a>
//Js
jQuery('.ajaxlink').live('click',function(e){
e.preventDefault(); /*Prevent default behavior of links*/
var url= $(e.target).attr('href');
/*
Now u have url, do post or get:
then append received data in some DOM element.
*/
});
//Controller
public ActionResult()
{
if(Request.IsAjax())
{
/*Return partial content*/
return View();
}
else
{
return View("SomeOther_View.cshtml");
/*
At this point you may reject this request or return full view
whatever you feel is okie.
*/
}
}
This way both type of users can be handled javascript enabled and javascript disabled.
Same can be done for forms.
Implementing a Javascript routing engine wouldn't be too difficult. First, serialize the Routes from C# to Javascript. Second, recreate the Url.Action method.
However, that's a bit overkill for any of the projects I've worked on. My team's projects have always rendered a common Javascript variable that holds all necessary URL's.
This approach ensures strongly-typed action methods and lends better to refactoring too.
This is easier said than achieved in practice, but your website should be fully functional with JavaScript turned off. When this is achieved, you should be able to add AJAX support to your website and re-use existing HREF attributes in your anchor tags or action attributes in your FORM tags. The website will be easier to maintain as you won't need to update links in your JavaScript files.
I've decided to implement my own UrlFactory, using ASP.NET helpers directly (Html/Url) in my code, now I don't have the src with me, I'll post'em tomorrow.
Pros on this: I can track each and every url easily and perform some rewriting in a centralized fashion.
Example of usage:
#{
string myAjaxUrl = UrlFactory.GetUrl (ActionName, ControllerName, new { query-params });
}
Then using 'em in javascript with
var jsUrl = '#myAjaxUrl';
Once you've defined your own Factory, you can hijack "important" urls (eg. for rewriting), and leave common to the Url helper implementation.
However for having this fully client side, there's an extra step of rendering a Js routing context, for accessing client side variables.
EDIT: As promised my very simple Url class builder:
public static class UrlFactory
{
public static string GetUrl(string Action, string Controller, object RouteValues)
{
UrlHelper Url = new UrlHelper(HttpContext.Current.Request.RequestContext);
return Url.Action(Action, Controller, RouteValues);
}
// Common URLS for Denied et similars.
public static string GetDeniedUrl(PEDUtenti Utente, object RouteValues)
{
return GetUrl(Utente, "Denied", "Errors", RouteValues);
}
public static string GetDeniedUrl(object RouteValues)
{
return GetUrl("Denied", "Errors", RouteValues);
}
}
Related
I should think this problem could come to anyone, I'm interested in ways of making the best use of technology to keep my code-base DRY and in sync.
I'm developing an ASP.NET MVC5 web application. I have several variables I need to be communicating to the client side. Say "PageType", which I need to be tracked on the client side using Google Analytics. The intent may be multifarious, this is a simple application with the same purpose, for illustration.
I have a C# class which allows me to specify the various PageTypes and also switch between them for switch-casing, say:
public static class PageTypes {
public const String Home = "Home";
public const String AboutUs = "AboutUs";
public const String ContactUs = "ContactUs";
}
This is useful when we check dynamic values, like:
String pageType = ViewBag.PageType;
if(!String.IsNullOrWhiteSpace(pageType))
{
switch(pageType)
{
case PageTypes.Home:
// do something here
break;
case PageTypes.AboutUs:
// do something else here
break;
...
... or even when doing comparisons. I hope you get the point.
So, in a Razor View, I can output var pageType = '#ViewBag.PageType'; in a page in an inline script, and it will be present as var pageType = 'Home'; or some such as the case, in the inline javascript of the page.
Now, just as I did with the C# code, I want to be able to switch-case the page type inside my javascript.
// This part is dynamic so will be inline script of the razor view
var pageType = 'Home';
// This part is logic so can reside in an external script
// This part is just illustration, I will worry about naming and accessibility later
// This will be in a separate script and will be included, and will be referenced, thereby providing Intellisense within Visual Studio
var PageTypes = {
Home: 'Home',
AboutUs: 'AboutUs'
};
// I should be able to do this, in an external script
switch(pageType){
case PageTypes.Home:
alert('Home!');
break;
case PageTypes.AboutUs:
alert('Not Home');
break;
default:
alert('Nothing');
break;
}
It can be seen that if the static class PageTypes of C# is in sync with the var PageTypes in the JavaScript, it would be a boon to our developers, with the Intellisense and predefined values, so that they may avoid typos and incompatibilities of values.
What's the best way to achieve this, while gaining Intellisense in both C# and JavaScript?
I would prefer changes in C# affecting JS rather than the reverse. The switch statements need not be converted, only the constant values like what I have mentioned.
I think a script in the build process could be useful but is there any tool/plugin/alternate way to accomplish what I have mentioned?
If I have understand what the problem is, what you can do is:
set the pagetype in some variable inside your html markup, using the template engine (sorry, I don't work with .Net, don't know how to write it). In this example, I used the data-* in the body element
< body data-type="%some template engine syntax that output the page type%">
in your js, retrieve the data-type value (in the example, I used jquery)
var type = $("body").data("type");
define some functions, each one for your pagetype, inside an key/object variable / object
var PageTypeFunctions = {
home: function() {
},
aboutus: function() {
},
xpto: function() {
}
}
invoke the function from the
PageTypeFunctionstype;
With this approach, you won't have to deal with the PageTypes variable. You will only need one function for each pagetype. Of course you can do some check to validate if PageTypeFunctions[type] exists.
We are building large ASP.NET applications for the intranet use in multiple languages/cultures. We utilize the Globalization with RESX files and use GetResourceText on the server side to get the localized texts.
Lately we are doing more and more client side logic with JQuery.
How do I get the RESX texts to be used in Javascript?
e.g. texts used for validation, dynamic messages etc.
All our Javascripts are in .JS files, we do not want to mix HTML in the ASPX page and Javascript blocks.
Thanks for your help.
Unfortunately, in an external JS file the server side code is not being processed by the server. However I have seen a workaround where you can set your translated values in hidden fields on the page - this way your javascript will be able to read the values in.
For example:
<%-- This goes into your page --%>
<input type="hidden" id="translatedField" name="translatedField" value="<%=Resources.Resources.translatedText %>" />
and use this inside your javascript file:
// This is the js file
$(document).ready(function() {
alert($("#translatedField").attr("value"));
});
You will be able to separate the values and still see it in your external JS file.
There is also another workaround that creates a .aspx file that only outputs Javascript instead of HTML. Check out the link below:
Using server side method in an external JavaScript file
Always separate functionality from human readable strings.
If you're creating jQuery-plugins you should be able to pass an array of localized strings as parameter when you call your different jQuery functions. The array could be defined as inline javascript directly on the page calling the different jQuery plugins or you could load the from external resource in the format /scripts/localization/strings.js?ci=en-US and register a Generic ASP.Net Handler in web.config that would respond to scripts/localization/strings.js
The DatePicker control is a fine example of how to localize text for the jQuery datepick control - this js file is dynamically created from resource files (resx) and when included on a page it will make sure the calendar control will have danish text.
Create a HttpHandler (.ashx file), and return JSON with your text resource strings.
You may also "publish" it to global namespace, i.e.
Response.Write("window.Resources=");
Response.Write((new JavaScriptSerializer()).Serialize(strings));
set up HTML like:
<script src="Resx.ashx?lang=en-US" />
<button class="LogoutButtonResourceId OtherButtonClasses">(generic logout text)</button>
<a href="#"><span class="SomeLinkTextResourceId OtherClasses">
(generic link text)
</span></a>
and apply texts like this:
$(document).ready(function() {
for(var resId in Resources){
$("."+resId).html(Resources[resId]);
}
});
If you don't want to use ASP.NET to generate your main JavaScript, here are two other options:
Use ASP.NET to generate a script file that contains variable-to-string assignments, such as var mystring = 'my value';. Your main script would then reference the localized text with variables names rather than as embedded values. If that's still too "dirty" for you, you could encode the strings as JSON rather than as variable assignments, using an HttpHandler rather than straight .aspx.
Have your JavaScript code issue an Ajax call to retrieve an array or list of localized strings from the server. The server-side part of the call would retrieve the text from your resx files.
Have you considered using $.ajax in combination with ASP.NET WebMethods? It's hard to suggest a more concrete solution to this problem without understanding how your JavaScript/jQuery would consume/process the resources. I assume that they're organized into logical groups (or could be) where you could return several resource strings that belong on a single page.
Assuming that, you could write a very simple C# class -- or use a Dictionary<string, string> -- to return data from your ASP.NET WebMethod. The results would look something like:
[WebMethod]
public Dictionary<string, string> GetPageResources(string currentPage)
{
// ... Organizational stuff goes here.
}
I always separate out my AJAX calls into separate .js files/objects; that would look like:
function GetPageResources (page, callback)
$.ajax({ // Setup the AJAX call to your WebMethod
data: "{ 'currentPage':'" + page + "' }",
url: /Ajax/Resources.asmx/GetPageResources, // Or similar.
success: function (result) { // To be replaced with .done in jQuery 1.8
callback(result.d);
}
});
Then, in the .js executed on the page, you should be able to consume that data like:
// Whatever first executes when you load a page and its JS files
// -- I assume that you aren't using something like $(document).ready(function () {});
GetPageResources(document.location, SetPageResources);
function SetPageResources(resources) {
for (currentResource in resources) {
$("#" + currentResource.Key).html(currentResource.Value);
}
}
I know it's to late but want share my experience in this task)
I use AjaxMin. It can insert resx key values into js file on build event.
It's not common way but it keeps html without unneeded script blocks and can be done during minification process if you have it.
It works like this:
ajaxmin.exe test.js -RES:Strings resource.resx -o test.min.js
Also you need to do the same for ech locale if you have many.
Syntax to write resource keys in js (and also css) is written here:
Js localization
Css localization
How about injecting it as part of a javascript control initialization? what i do is as follows:
I have a self-contained javascript control - call it CRMControl, which has an init method called setupCRMControl, to which i pass a settings object. When i initialize it, i pass an object containing all the resources i need inside javascript as follows:
CRMControl.setupCRMControl({
numOfCRMs: 3,
maxNumOfItems: 10,
// then i pass a resources object with the strings i need inside
Resources: {
Cancel: '#Resources.Cancel',
Done: '#Resources.Done',
Title: '#Resources.Title'
}
});
Then, inside this javascript control:
var crmSettings = {};
this.setupCRMControl(settings) {
crmSettings = settings;
};
and whenever i want to show a resource, i say (for example, show an alert saying 'Done'):
alert(crmSettings.Resources.Done);
You can call it "R" to make it shorter or something, but this is my approach. Maybe this may not work if you have a whole bunch of strings, but for manageable cases, this may work.
What options or libraries are out there for building html from a returned ajax response?
Currently I am taking the json data I receive, building the html as a string, and using a jQuery DOM insertion function, but I have to think there is a better and more maintainable way out there to do what I am trying to do.
For example, I have a page with a list of projects, with just a thumbnail and title, which users can click on. Once a project is clicked and the json request comes back successfully, more detailed project information is shown. Currently I am doing something that is essentially:
build_project = function(data){
var projectHTML = "<div id='projectData_"+data.id+"'>"+data.contents+"</div>";
return projectHTML;
}
Then inserting it into the DOM where it needs to go. The problem arises when there is more than just one element, sometimes I'll have to create up to 6-10 different nested elements with stuff like the below cropping up:
projectHTML += "</div>";
projectHTML += "</div>";
projectHTML += "</div>";
I'm aware of mustache.js, but I'm not sure if that is exactly what I'm looking for or not - and whether there are any other options that I should investigate.
Thanks!
You are on the right track. Take a look at the jquery.tmpl library.
http://api.jquery.com/jquery.tmpl/
You can try http://knockoutjs.com/ alongside with JQuery templates.
"Knockout is a JavaScript library that helps you to create rich, responsive display and editor user interfaces with a clean underlying data model. Any time you have sections of UI that update dynamically (e.g., changing depending on the user’s actions or when an external data source changes), KO can help you implement it more simply and maintainably."
You can make a printf style method in JavaScript.
You can live dangerously and extend the String object (as luck would have it I wrote this a couple of days ago)...
String.prototype.printf = function() {
var theseArguments = Array.prototype.slice.call(arguments).reverse(),
argumentsLength = theseArguments.length,
str;
str = this.replace(/%s/g, function() {
return theseArguments[--argumentsLength];
});
return str;
};
jsFiddle.
...or simply make it a normal function, and perhaps faux namespace it as util.printf = function() { ... }.
Of course, the function above isn't really printf() (it handles string interpolation only), but you could extend it to do integers, floats, padding, etc.
If you are using ASP.Net and if you do not need the JSON result on the client (other than to do DOM-insertions) you could render the html on the server.
You could then take advantage of you programmning language functionality to build up the html.
Finally you return the HTML-string and append it to you DOM.
As an example you can create your DOM-elements like this:
var panel = new Panel();
var label = new Label { Text = data.contents };
panel.Controls.Add(label);
return panel.ToHtml(); //use stringwriter
This teqnique have proven very useful in several projects i have been involved in.
another option which maybe more maintainable, testable etc would be for your remote function itself (that your calling via ajax) to return the formatted html instead of the data. For example in MVC, e.g ASP.NET MVC, you can return a view and the script would take this data as is without having to manipulate it.
[AcceptVerbs((HttpVerbs.Get))]
public ActionResult GetView(string param1)
{
var model = new ModelXXX;
...
...
return View("ViewName", model);
}
I just started to investigate mvc on javascript client side (JavaScript MVC). Everything looked great until I got to form submitting :) View part won't do it, that's simple. Event is attached in Controller, so Controller is good place to validate form data, but I'm not sure I want my Controller to know specific server address (were to post my form), so would be great to have a method in Model, but then I don't want my Model to know about my Form (which is actually html structure...).
Well, what do I miss about MVC conception? I am also not sure I want to serialize my form in Controller and then pass it as parameter to my Model. For now, the only option I see to make Model independent is to have JavaScript structure (entity), which will be filled by controller (based on form data) and will be passed to the Model method to be saved on server. Very smplified code:
Info = {
name,
address,
// 15 more properties
...
}
InfoController = {
...
onFormSubmit: function() {
...
info.name = document.getElementById("info-name").value;
info.adress = document.getElementById("info-address").value;
...
InfoModel.save( info );
}
}
InfoModel = {
...
save: function( info ) {
// here some code to setialize info object
// send it to server
...
}
}
But it makes my code too complicated (comparing to simple form serizlization by some side frameworks and just sending it..). What's the right choice?
Just answering my own question. Short answer - yes, I was right with my assumptions ;)
I took a look at JavaScriptMVC, and noticed one simple thing I missed, a simple function can be developed which will create javascript object based on form (they have function called formParams which performs this type of converting). This way my controller is simplified:
InfoController = {
...
onFormSubmit: function() {
...
var info = $infoForm.formParams();
InfoModel.save( info );
}
}
Now it does not look that complicated, and its advantage is that there is one place (model) which knows how to save data (validation; url to send; some other stuff like add this entity to client side 'storage'; firing an event that something new is going to be created; whatever else according to our needs), and if I have one more place, or control flow to perform this operation again I won't write this code again, and it does not depend on presentation (is it form, or just set of inputs, wizard etc.). Also Model becomes quite reusable.
Actually before using this approach we had something similar, but it was not that structured (among different presentations for my application which can run javascript).
Building a browsergame I came from PHP to JavaScript, which I now also want to use at the server side.
As I'm going to require Users to have JavaScript either way, I'm going to take extensive use of it. I want to use in in a object-oriented way though.
Considering MVC, Models will be used on both client and server side. Views are only used at the client side.
The interface is split into multiple parts: a main sidemenu, main content and some widgets. I'll take the part I've already done as example:
The menu is split into three categories with multiple entries. Each entry is a link with an attached action (like switching the content).
// menuview:
var self = new View();
var generalMenu = new MenuCategory('generalmenu')
.addEntry(new MenuEntry('overview', new Action()))
.addEntry(new MenuEntry('buildings'))
.addEntry(new MenuEntry('resources'))
// [..more categories..]
self.toData = function() {
return {
id: this.id,
cat: [generalMenu.toData(), infosMenu.toData(), userMenu.toData()]
};
};
At the moment View is a compositum with a toData() method to create data for the template parser(selfmade, simple but supporting iteration). And the actions get attached after creation. I use jQuery as framework:
self.show = function(callback) {
$tpl(this.tpl).parse(this.toData()).lang('main').toHTML(function(html) {
var el = $(html);
el.find('a').click(function (e) {
MenuEntry.actionHandler.execAction(e.target.id);
return false;
});
el.appendTo('#'+self.target);
callback && callback();
});
return this;
};
I have declared an actionhandler to avoid iterating over the links.
I'm not feeling well with this solution, it's not flexible enough. I'd like to treat a view like a real compositum, not with a lot of strange dependencies. Also, I have to reparse the whole View if I change a part. Well, in this example this is not obvious, because the menu wont change while runningtime, but other parts of the interface will.
Now, to finally get to my question: Is there a better solution?
Like having dom references spread over the view, each menuentry having it's own reference and directly attached action? If I'm not using templates anymore, what kind of flexiblity am I losing?
I decided to go without template parser. Each view stores it's node and is able to manipulate it directly if it gets informed to update the data.