How to generate RDF/XML using a template in javascript? - javascript

I have some working Javascript code that generates an RDF/XML document using variables picked up from HTML fields:
...
peopleDoap += " <foaf:name>" + person_name + "</foaf:name>\n";
if (person_url != "") {
peopleDoap += " <foaf:homepage rdf:resource=\"" + person_url + "/\"/>\n";
}
if (person_pic != "") {
peopleDoap += " <foaf:depiction rdf:resource=\"" + person_pic + "/\"/>\n";
}
...
It's hard, looking at this code, to get any sense of what the output will look like (especially as this code is scattered amongst sub functions etc).
I'm wondering if there is an easy way that would enable me to have something like this:
...
<foaf:name>%person_name%</foaf_name>
<foaf:homepage rdf:resource="%person_url%"/>
<foaf:depiction rdf:resource="%person_pic%"/>
...
And then some substitution code. One slight complication is if fields are left blank, I will want to not generate the whole element. Ie, if person_url='', the above should generate as:
...
<foaf:name>%person_name%</foaf_name>
<foaf:depiction rdf:resource="%person_pic%"/>
...
I guess I could do this fairly naively by defining the template as a huge string, then performing a bunch of replaces on it, but is there anything more elegant? Mild preference for native Javascript rather than libraries, but happy to be convinced...
(Btw, yes, since this is RDF/XML, maybe there is a smarter way using some kind of RDF library. If you want to address that of the question instead, that's ok with me.)
Code is here.
Also, this is a widget running on a Jetty server. I don't think server-side code is an option.

I recommend using:
jQuery Templates
Mustache
John Resig's Micro-Templating
jQuery Templates are very powerful and nicely integrated with jQuery. That means that you can do things like this:
$.tmpl("Hello ${n}", {n: "World"}).appendTo('h1');
for the most simple stuff, or define templates in your HTML inside special script tags with custom MIME types, compile them, populate them with JSON data from AJAX calls, etc.

To add a bit of follow-up, I did implement John Resig's Micro-Templating (actually the refined version I posted earlier). However, I then backpedalled a bit. I found implementing control structures in the template is less readable than outside:
...
'<description xml:lang="en">#description</description>';
if (homepage) t +=
'<homepage rdf:resource="#homepage"/>';
...
rather than:
...
'<description xml:lang="en"><#= description #></description>' +
'<# if (homepage) { #>' +
'<homepage rdf:resource="<#= homepage =>"/>' +
'<# } #>';
...
I also ditched the microtemplating code for a simple substitution of variables, using #var rather than <# var #>.
Readability of templates like this is really critical, so I've done everything I could think of. In particular, keeping the javascript outside of the template lets syntax highlighting work, which is valuable to me.
That John Resig post also suggested burying the template in your HTML, in a but I preferred to keep it in my javascript, which is a separate .js.

Related

amp value replace in place

I have an amp-list which loads bunch of data and I show them in their respective placeholders just nice and easy. What I intend to do is get a value and run a simple script on it. Let's think I have
<div>{{title}}</div>
where title is: 'This-is-my-title'
now I would like to replace the '-' in title, I know I could do it with javascript using title.replace(/-/g,' '), how can I do that in place?
I tried
<div>{{title.replace(/-/g,' ')}}</div>
but no luck :(
In plain javascript the following:
title = 'This-is-my-title'; title.replace(/-/g, ' ');
gives you "This is my title".
I am guessing you are using angular, in that case the text within {{ }} is not evaluated as a pure javascript expression. You could write an angular filter to apply to the expresssion (as described in Angular filter to replace all underscores to spaces ). It would probably be easier to handle this in the controller behind the template. Something like:
$scope.title = $scope.title.replace(/-/g,' ');
Looks like you are using amp-mustache. I don't think there is a way for you to use custom JavaScript in Mustache.js here, and restrictions from AMP prevent you to create some kind of function that you can call in {{}}. I would suggest processing in the backend before sending. (Also unfortunately, there are no other templates other than mustache available at this point)
There is a workaround on math using amp-bind here: AMP Mustache and Math
So probably after loading the JSON with amp-state, something like
myItems.map(entry => ({
myString: entry.myString.split('').map(c => c == '-' ? ' ' : c).join('')),
})
might work (I have not tested myself but worth a try, check whitelisted functions here: https://www.ampproject.org/es/docs/reference/components/amp-bind#white-listed-functions) but might still be a pain performance-wise (amp-bind has quite a bit overhead)
Edit: this actually looks quite promising, just found out actually amp-list with amp-bind do accept object for [src], as described in the doc (learning something new myself): https://www.ampproject.org/docs/reference/components/amp-bind
(checked amp-list source code and should work)

Is there a better way of creating elements and appending text to/around them?

I currently have a bunch of lines that look like:
txt = "Can't print the value for <span class='keyword'>"+arguments[1]+"</span> before it's set";
I'm then doing
$('#mydiv').append($('<div/>').html(txt));
This looks terrible and I need to escape any html inside arguments[1]
The only alternative I can think of is to make sure all the text is inside its own element:
var spans = [];
spans[0] = $('<span/>').text("Can't print the value for ");
spans[1] = $('<span/>').text(arguments[1]).className('keyword');
spans[2] = $('<span/>').text(" before it's set");
$('#mydiv').append($('<div/>').append(spans[0],spans[1],spans[2]));
This is quite a lot for just a simple line of text. Is there anything else I can do?
edit: This isn't something that should be handled by a templating engine. It's html generated by a javascript logging function.
If It's a consistent format, I'd add it as a normal string and then do a search for the keyword part.
$('<div/>')
.appendTo('#mydiv')
.html("Can't print the value for <span class='keyword'></span> before it's set")
.find('.keyword').text(arguments[1]);
If you will be continuing to create lots of HTML using JS, I would suggest working with a templating library. I am a recent convert, it took me a long time to understand the point. But seeing many successful sites (twitter,github,etc.) and the great John Resig promote and/or make heavy use of templating, i'm glad I stuck with trying to understand. Now I get it. It's for separation of concerns, keeping logic out of the view.
I'm using this very bare bones templating library: http://blueimp.github.com/JavaScript-Templates/ though the templating provided by underscore.js and mustache.js are more popular.
The advantage of the library i'm using is its really small, <1kb and is basically like writing php/asp code if you are familiar with those.
you can write HTML inside <script> tags without having to escape:
using your variable, txt, the syntax looks like this:
<script>
var data={txt : "Can't print the value for <span class='keyword'>"+arguments[1]+"</span> before it's set"};
<div>{%=o.txt%}</div>
</script>

Javascript-better method of writing HTML

This problem is about Javascript writing HTML code for video player. I think there are some faster methods(document.createElement,Jquery and etc). Please tell some better and faster methods for this procedure. Thanks in advance
function createPlayer(videoSource){
document.writeln("<div id=\"player\">");
document.writeln("<object width=\"489\" height=\"414\" >");
document.writeln("<param name=\"player\" value=\"bin- debug/FlexPlayer.swf\">");
//etc
document.writeln("</embed>");
document.writeln("</object>");
document.writeln("</div>");
}
Going native with document.createElement will be the fastest. However, if your markup is large, going this way makes it a maintenance nightmare. Also, it is not easy to 'visualize' things.
In those cases, you might want to go for a tradeoff with client side templating solutions such as jQuery templates or underscore templates or John Resig's microtemplating.
Another performance boost is to build your entire markup and add it to DOM at the very end (add children first, then add the parent to DOM).
There is a jQuery function I know of that allows you to create a template HTML snippet which you can later use repeatedly with only 1 or 2 lines of code, adding in variables and appending it to the page.
For this you will need jQuery (latest should be fine) http://jquery.com/
Docs for the tmpl function are here: http://api.jquery.com/jquery.tmpl/
For details on how to use it you'd be best reading an example on the jQuery docs, I've not used it myself so can't write you a good example but there is great stuff on the docs site.
Hope this helps
EDIT:
A less resource intensive way to acheive that function would be to, rather than writing each line in turn to the document, just append them all to a string and then write that once when you are finished.
Eg:
function createPlayer(videoSource){
var html="<div id=\"player\">";
html+="<object width=\"489\" height=\"414\" >";
//etc
document.writeln(html);
}
This is faster because writing a line to the document uses more resources than just appending a string in memory. For MAXIMUM SPEED you could even declare the html var outside of the function and just set it to the markup as one long string, then write it - i.e
var html;
function createPlayer(videoSource){
html="<div id=\"player\"><object width=\"489\" height=\"414\" >"; //and so forth
document.writeln(html);
}
If you can justify the larger download sizes I'd go for the jQuery solution if possible, it's generally a bit more manageable - I've done plenty script generated HTML in the past and it very quickly becomes a pain to maintain. Good luck
You can try this:
function createPlayer(videosource){
var div = document.createElement('div');
div.innerHTML = '<object width=\"489\" height=\"414\" >' +
'.......'
document.body.appendChild(div);
}
For general manipulation and addition of HTML I'd recommend jQuery. It makes the process much easier and quicker.
You will find more information on this here:
jQuery Manipulation Methods - http://api.jquery.com/category/manipulation/
jQuery Tutorials - http://docs.jquery.com/Tutorials

ASP.NET inline server tags

I'd like to start by saying that my code is working perfectly, this is more a "how best to do it" kind of question.
So I have code like this in my .aspx file:
function EditRelationship() {
var projects=<%= GetProjectsForEditRelationship() %>;
// fill in the projects list
$('#erProjectsSelect').empty();
for(var i in projects)
$('#erProjectsSelect').append('<option value='+projects[i][0]+'>'+projects[i][1]+'</option>');
var rels=<%= GetRelationshipsForEditRelationship() %>;
// etc
}
Again, it's working fine. The problem is that VS2008 kinda chokes on code like this, it's underlining the < character in the tags (with associated warnings), then refusing to provide code completion for the rest of the javascript. It's also refusing to format my document anymore, giving parsing errors. The last part is my worst annoyance.
I could put some of these in evals I guess, but it seems sorta dumb to add additional layers and runtime performance hits just to shut VS up, and it's not always an option (I can't remember off the top of my head where this wasn't an option but trust me I had a weird construct).
So my question is, how do you best write this (where best means fewest VS complaints)? Neither eval nor ajax calls fit this imo.
If your aim is to reduce VS complaints, and if you are running asp.net 4 (supporting Static client Ids), maybe a strategy like the following would be better?
Create a ASP:HiddenField control, set its ClientIdMode to "Static"
Assign the value of GetRelationshipsForEditRelationship() to this field on page load
In your javascript, read the value from the hidden field instead, I assume you know how to do this.
It's more work than your solution, and you will add some data to the postback (if you perform any) but it won't cause any VS complaints I guess :)
You could do this from your page in the code-behind
ClientScript.RegisterArrayDeclaration("projects", "1, 2, 3, 4");
or to construct something like JSON you could write it out
ClientScript.RegisterClientScriptBlock(GetType(), "JSONDeclarations", "your json stuff");
UPDATE Based on my comment
<script id="declaration" type="text/javascript">
var projects=<%= GetProjectsForEditRelationship() %>;
var rels=<%= GetRelationshipsForEditRelationship() %>;
</script>
<script type="text/javascript">
function EditRelationship() {
// fill in the projects list
$('#erProjectsSelect').empty();
for(var i in projects)
$('#erProjectsSelect').append('<option value='+projects[i][0]+'>'+projects[i][1]+'</option>');
}
</script>
I don't have VS2008 installed to test with, so take this with a grain of salt, but have you tried something like this?
var projects = (<%= GetProjectsForEditRelationship() %>);
Something like that might trick the JavaScript parser into ignoring the content of your expression.
For what it's worth, VS2010 correctly parses and highlights your original code snippet.
Is it an option to move this to VS2010? I just copied and pasted your code and the IDE interpreted it correctly.
The best solution is to put javascript in a separate file and avoid this entirely. For this particular function, you're doing server-side work. Why not build the list of options that you intend to add dynamically in codebehind, put them in a hidden div, and then just have jQuery add them from the already-rendered HTML?
If you have a situation where you really want to dynamically create a lot javascript this way, consider using ScriptManager in codebehind to set up the variables you'll need as scripts and register them, then your inline script won't need to escape
ScriptManager.RegisterClientScript("projects = " + GetProductsForEditRelationship());
(Basically, that is not the complete syntax, which is context dependent). Then refer to "projects" in your function.
(edit)
A little cleaner way to do this on a larger scale, set up everything you need like this in codebehind:
string script = "var servervars = {" +
"GetProductsForEditRelationship: " + GetProductsForEditRelationship() +
"GetRelationshipsForEditRelationship: " + GetRelationshipsForEditRelationship() +
"}"
and refer to everything like:
servervars.GetProductsForEditRelationship
If you do this a lot, of course, you can create a class to automate the construction of the script.

Is there a better way populate HTML widgets than building strings and setting innerHTML?

With XML XSLT, it is possible to build a nice template in HTML, convert it to XSLT and use xml data coming from the server to dynamically populate widgets on the client side.
JSON and JSONP are great for interacting with the server side and manipulating the data in JS. When it comes to rendering the JSON data, most examples I've seen use JS to concatenate an ugly string and set the innerHTML of some element to render it.
Is there an easy browser compatible way of creating html widgets and populating them with JSON that doesn't involve string banging or building loads of DOM elements?
As mentioned in other answers, what you're looking for is a javascript based templating language. There is a pretty good list going in this related question. Just to highlight a couple, mustache is clean, simple and ported to many many languages. I believe its being used by Twitter. Google Closure has template language that works in both JavaScript and Java. That's been battle tested by Google obviously.
Other major JS libraries each have templating as plugins or part of the library. I know jQuery has at least one plugin and is planning one on the roadmap for v1.5. Dojo has a clone of Django's templating language that looks pretty nice.
There are others, but I think that's going to be the cream of the crop.
I don't actually use any of these, because I use a home grown one, but I can tell you that they are very nice to work with and I highly recommend them over string concatenation or doing more work on the server.
You should see this blog post by John Resiq: JavaScript Micro-Templating
It has a simple micro-templating code you can re-use. It goes like this:
// Simple JavaScript Templating
// John Resig - http://ejohn.org/ - MIT Licensed
(function(){
var cache = {};
this.tmpl = function tmpl(str, data){
// Figure out if we're getting a template, or if we need to
// load the template - and be sure to cache the result.
var fn = !/\W/.test(str) ?
cache[str] = cache[str] ||
tmpl(document.getElementById(str).innerHTML) :
// Generate a reusable function that will serve as a template
// generator (and which will be cached).
new Function("obj",
"var p=[],print=function(){p.push.apply(p,arguments);};" +
// Introduce the data as local variables using with(){}
"with(obj){p.push('" +
// Convert the template into pure JavaScript
str
.replace(/[\r\t\n]/g, " ")
.split("<%").join("\t")
.replace(/((^|%>)[^\t]*)'/g, "$1\r")
.replace(/\t=(.*?)%>/g, "',$1,'")
.split("\t").join("');")
.split("%>").join("p.push('")
.split("\r").join("\\'")
+ "');}return p.join('');");
// Provide some basic currying to the user
return data ? fn( data ) : fn;
};
})();
So you template would be in the markup:
<script type="text/html" id="item_tmpl">
<div id="<%=id%>" class="<%=(i % 2 == 1 ? " even" : "")%>">
<div class="grid_1 alpha right">
<img class="righted" src="<%=profile_image_url%>"/>
</div>
<div class="grid_6 omega contents">
<p><b><%=from_user%>:</b> <%=text%></p>
</div>
</div>
</script>
To use it:
var results = document.getElementById("results");
results.innerHTML = tmpl("item_tmpl", dataObject);
To be clear - the above example was taken from the blog post and is not my code. Follow the link for more info.
You could use jQuery and some sort of jQuery Plugin for Templates. For example http://ivorycity.com/blog/jquery-template-plugin/ (have a look at this page, there are some nice samples)

Categories

Resources