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);
}
Related
I came across a strange requirement (set by myself)...
I'm creating an easy to integrate ajax content loader plugin with lots of options and callbacks. Since the loader is a class and the developer can have multiple instances on a single page, I wanted to get rid of all the ugly code required for every single initialization and decided to use data attributes instead - they look awesome and proficient!
The question is: How to add functions and javascript in general inside a data attribute?
Example:
var url = "someurl/goes/here/";
var Template = new TemplateEngine('Name', {
onCreate: function(template, parts) {
// do something with template parts
template.ID += 1;
},
onRender: function(template, parts) {
template.addClass('flash');
}
});
var settings = {
container: DOM_ELEMENT|STRING,
template: Template,
disableDefaultRender: true,
// a bunch of hooks and callbacks like this:
onBeforeRequest: function(loader, data) {
new_data = data;
// modify request data somehow
loader.requestData = new_data;
},
onRender: function(loader, data) {
loader.renderData(data, function(part) {
// define specific rendering logic for different template parts
// in required
});
},
onAfterRequest: function(loader, data) {
},
onError: function(loader, data) {
}
// etc, etc
};
var THE_LOADER = new SuperFancyAjaxLoader(url, settings);
My original idea is to somehow put all of the above inside the said data attribute:
<div data-fancy-stuff="{all-or-most-of-the-above}">more stuff</div>
and make the script itself find all elements and initialize instances for each of them like so:
var elements = document.querySelector('[data-fancy-stuff]');
for(item in elements) {
try {
var data = elements[item].getAttribute('data-fancy-stuff');
var THE_LOADER = new SuperFancyAjaxLoader(data.url, data.settings);
} catch (ex) {
console.log('Someone messed with prototypes');
}
}
Is the idea of putting javascript functions inside an attribute idiotic? Or is there a way to actually put some js inside an attribute?
I understand that if there's so much javascript required, it's pointless to try and put it inside an attribute, but in real life cases (for this particular task), I will have 3-5 content loaders per page, most of them (or all) will use the same template and rendering logic, but they will all have to modify the request data differently by themselves.
p.s. Eval is Evil.
edit: I'm open to design proposals which do not involve third party MVC frameworks.
May be I don't understand well, but You want provide some JavaScipt modules/classes/objects through HTML5 attribute???
I think it's bad design. It's seems to be mixin of distinct layers.
So technically U have just ONE ability - to call eval, even after your PS because eval is the only point where JavaScript can get other JavaScript from String - ONLY.
But if U want dynamically load some complex javascript as reaction to data in some elements it's very good idea to learn and apply most ultimate thing for such scenarios - well-old-knownn require.js http://requirejs.org/. And if you want hardly bind DOM with some data and behavior you must to learn some of MVC JavaScript solutions - AngularJS, Backbome, Amber and so on.
By design u have to split your application to presentation layer where DOM will live and business layer were JavaScript will live. To bind them to each other you use string/JSON descriptors in DOM attribute and load JavaScript dynamically using on-fly head rewriting or by XHR+eval, such design is asynchronous, quick and is main choise of all solid network-based applications from gmail to all-other-cool-staff. To help build application with such model - require.js is best and most known helper.
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);
}
}
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.
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.