I am using mustache to build out a single string, replacing several variables within it. I would love to use a TemplateString instead, but I need to resolve my string at runtime, and not at code-compile time since I am reading the template string from an external source.
To be clear:
// mustachy example
// template is "foo{{who}}" and myData.whmustao = "manchu"
let myResult = mustache.render(getMyTemplate(),myData);
console.log(myResult); // "foomanchu"
This is pretty lightweight, and I would love to use a TemplateString, but as the example below aludes to - I can't imagine a way to externally provide the string in the first place...
// ES6xy example
let myResult = `foo${myData.who}`; // can't get this at runtime
console.log(myResult); // "foomanchu"
But, I can't imagine a straight-forward, clean, non-sneaky way of achieving this. Can you?
I'm assuming that you're loading data on the client and want to generate a string based on the data returned. You could have a function available that returns the generated string for you
function generateString(val1, val2) {
return `foo${val1} bar${val2};
}
can you call that function on the client as a result of an api call that gets val1 and val2?
this strategy would also work on the server if you delay your response until you have all the data you need
put the template-string into a function, and pass myData
let renderMyTemplate = data => `foo${data.who}`;
//or
let renderMyTemplate = ({who}) => `foo${who}`;
let myResult = renderMyTemplate(myData);
console.log(myResult);
Thank you for your replies and creative solutions. However, I thought that there was no solution because TemplateStrings are an in-code feature, whereas other template solutions (like mustache) are a data-driven feature.
Put in other words, ES6's Template Strings is a language feature which limits its functionality to static in-code strings. Any other imagined flexibilities must rely on dynamic execution of a code you inject into your application, which is every hacker's dream.
So the answer to my original thought, as to whether Mustache is overkill for a simple string that is not hard-coded in your source - is NO. Mustache is the acceptable solution for that scenario.
Related
Let's say I have a page called https://randompagename.com, I know I can send GET parameters to this page using this syntax: https://randompagename.com/?parameter1="one"¶meter2="two".
I also know that on a Node.js web app I have an easy way of getting these parameters inside a variable. However, when I'm using pure frontend Javascript without Node.js, I usually solve this problem with something like:
const myURL = decodeURI(window.location.href)
This way, I discover that my page is https://randompagename.com/?parameter1="one"¶meter2="two" and then I can parse it excluding everything after the first = sign and then splitting everything on &. Well, even though this is functional I'm probably missing an easier way of solving this problem. How can I get GET parameters on a page without using any library?
You can use the URL object https://developer.mozilla.org/en-US/docs/Web/API/URL
If the URL of your page is https://example.com/?name=Jonathan%20Smith&age=18 you could parse out the name and age parameters using:
let searchString = (new URL(document.location)).search; //?name=Jonathan%20Smith&age=18
let params = (new URL(document.location)).searchParams;
let name = params.get('name'); // is the string "Jonathan Smith".
let age = parseInt(params.get('age')); // is the number 18
I am using less.js (1.3.0) to parse less to css on the client side. Inside the parsers' callback I want to get the value for each variable. i tried the following without success.
var data = "#colour: red; #example { background-color: #colour; }",
parser = new less.Parser({});
parser.parse(data, function (error, root) {
console.log( root.toCSS() );
var varsDef = root.variables();
for (k in varsDef) {
console.log(varsDef[k]);
// how to get the value for the var?
//not working
console.log(varsDef[k].eval());
//not working
console.log(varsDef[k].toCSS());
//is an object but looking for a string value
console.log(varsDef[k].value);
//returns an empty string
console.log(varsDef[k].value.toCSS());
}
});
Neither eval() nor the toCSS() gave me any results. I do not understand the less parsers' inner workings. Each variable object has a variable property varsDef[k].value which is an object itself. But I just need the string value of the variable.
Does anyone know how to get the variables' values as a string?
varsDef[k].value.toCSS()
should be the value
varsDef[k].name
should be the variable name
varsDef[k].toCSS()
returns nothing because it is a variable - in CSS variables do not output.
i ran into this problem recently and it bit me because, like you, i had the same instinct of running something like very much like the code you wrote above but for complex variables along the lines of
#redColor: #900; // responds to .toCSS()
#fooColor: desaturate(#redColor, 20%); // both of these error out
#barColor: lighten(#fooColor, 10%); // when calling .toCSS()
you'd get this nested tree.Value for #barColor which was this nested representation of the parse tree, so it would say, unhelpfully that barcolor: {[value: {value: [{lighten: {...}}]}]} or somesuch. my parsing-fu is pretty bad because i would always end up with some object at some point which would no longer respond to me invoking tree.toCSS on it, so i gave up on that route.
Instead, what i did was generated a nonsense .less file with an import rule and a nonsense rule, like so
#import "varfile.less";
.foo {
redColor: #redColor;
fooColor: #fooColor;
barColor: #barColor;
}
less will happily parse such a file, it doesn't care if redColor is a real css property or not, it just ignores it and does all the substitutions where it has to dutifully. And so you actually end up with a single rule css file that you can easily parse since it's very straightforwardly marked up. it looks like this:
.foo{
redColor: #990000;
fooColor: #8a0f0f;
barColor: #b81414;
}
this is, coincidentally, the easiest file to parse. it practically begs to be turned into json or what have you. granted, the path to here is pretty comical. i suspect it's because a variable without a rule is still fair game to be modified within the rule itself, but i could just be rationalizing that.
assuming you only want to extract the final values of your less vars and not the semantic values of your less vars, it's pretty handy. if you want semantics, it seems better to just parse the actual less file.
i ended up writing this in node and after i got past my own objections to how dodgy it felt, it worked quite well and fed me a json dict with my project's variables. you can take a look, it's on github at nsfmc/less-extractor which basically takes a basic config file and then writes to stdout a json dict. it's inelegant, but it totally works, even if it's a bit hackish.
your original question asked about doing this entirely client-side, so that would appear to rule out that github project, but the idea is very similar: you want to be able to access the original less file as part of some xhr request, parse it to get the variable names, build a less string, parse that, and then the rest of the code is just string building and run of the mill parsing.
hope that helps you!
I was also having issues with the less parser too; doing it that way was getting ridiculous with recursive checking of tree nodes.
If you wan't the actual values as opposed to the CSS generated (as per the above answer), the best way is to probably manually parse the file's text.
This function returns a key/value pair for each of the variables in a given less file. It wont work if the LESS file has multiple values per line, you could make it better with regex. I used it to parse bootstrap's variables file, which works nicely.
getLessVars = (lessStr) ->
lines = lessStr.split('\n')
lessVars = {}
for line in lines
if line.indexOf('#') is 0
keyVar = line.split(';')[0].split(':')
lessVars[keyVar[0]] = keyVar[1].trim()
return lessVars
I have a variable called "result",
var result;
that result value is equal to following value, please presume that is just a string :)
---------result value -----------
for (;;);{
"send":1,
"payload":{
"config":{
"website":"",
"title":"welcome to site",
"website-module":1313508674538,
"manufatureid":"id.249530475080015",
"tableid":"id.272772962740259",
"adminid":100002741928612,
"offline":null,
"adminemail":"admin#website.com",
"adminame":"George",
"tags":"web:design:template",
"source":"source:design:web",
"sitelog":[],
"errorlog":0,
"RespondActionlog":0,
"map":null
},
"imgupload":""
},
"criticalerror":[0],
"report":true
}
---------result value------------
From that value, I would like to extract tableid which is "id.272772962740259" with classic Javascript.
How can I extract the code, please let me know how can i do with simple javascript, please don't use Jquery, all I just need is simple javascript.
You can simply evaluate the value of the variable to obtain the values. However, please note that your current value is not valid JSON; that for(;;); at the beginning of the value invalidates the format. Remove that, and you can do this:
var object = eval('(' + resultMinusThatForLoop + ')');
alert(object.payload.config.tableid);
If that data is a string the parse it with a JSON parse. The following should get the value you want
JSON.parse(result).payload.config.tableid; // "id.272772962740259"
Edit: though, as Tejs says, the for(;;) invalidates the string and stops it from being parsed. If you can remove that, do.
You need to remove the empty for loop, then parse the string. DO NOT use eval; most modern browsers provide built-in JSON-parsing facilities, but you can use json2.js if yours does not. Assuming that you assign the results of parsing the JSON to result, you should be able to get that value using result.payload.config.tableid.
You should probably read a good JS reference. JavaScript: The Good Parts or Eloquent JavaScript would be a good choice.
If result is a javascript object and not a string, you can just use 'result.payload.config.tableid'.
If it is not, how do you get the AJAX result? Are you using XmlHttpRequest directly? Most libraries will give you a javascript object, you might be missing a flag or not sending the response back with the right content type.
If it is a string and you want to parse it manually, you should use a JSON parser. Newer browsers have one built in as window.JSON, but there is open source code for parsing it as well.
var obj = JSON.parse(result);
alert('tableid is ' + obj.payload.config.tableid);
I have been wondering if there is a way to define multiline strings in JavaScript like you can do in languages like PHP:
var str = "here
goes
another
line";
Apparently this breaks up the parser. I found that placing a backslash \ in front of the line feed solves the problem:
var str = "here\
goes\
another\
line";
Or I could just close and reopen the string quotes again and again.
The reason why I am asking because I am making JavaScript based UI widgets that utilize HTML templates written in JavaScript. It is painful to type HTML in strings especially if you need to open and close quotes all the time. What would be a good way to define HTML templates within JavaScript?
I am considering using separate HTML files and a compilation system to make everything easier, but the library is distributed among other developers so that HTML templates have to be easy to include for the developers.
No thats basically what you have to do to do multiline strings.
But why define the templates in javascript anwyay? why not just put them into a file and have a ajax call load them up in a variable when you need them?
For instantce (using jquery)
$.get('/path/to/template.html', function(data) {
alert(data); //will alert the template code
});
#slebetman, Thanks for the detailed example.
Quick comment on the substitute_strings function.
I had to revise
str.replace(n,substitutions[n]);
to be
str = str.replace(n,substitutions[n]);
to get it to work. (jQuery version 1.5? - it is pure javascript though.)
Also when I had below situation in my template:
$CONTENT$ repeated twice $CONTENT$ like this
I had to do additional processing to get it to work.
str = str.replace(new RegExp(n, 'g'), substitutions[n]);
And I had to refrain from $ (regex special char) as the delimiter and used # instead.
Thought I would share my findings.
There are several templating systems in javascript. However, my personal favorite is one I developed myself using ajax to fetch XML templates. The templates are XML files which makes it easy to embed HTML cleanly and it looks something like this:
<title>This is optional</title>
<body><![CDATA[
HTML content goes here, the CDATA block prevents XML errors
when using non-xhtml html.
<div id="more">
$CONTENT$ may be substituted using replace() before being
inserted into $DOCUMENT$.
</div>
]]></body>
<script><![CDATA[
/* javascript code to be evaled after template
* is inserted into document. This is to get around
* the fact that this templating system does not
* have its own turing complete programming language.
* Here's an example use:
*/
if ($HIDE_MORE$) {
document.getElementById('more').display = 'none';
}
]]></script>
And the javascript code to process the template goes something like this:
function insertTemplate (url_to_template, insertion_point, substitutions) {
// Ajax call depends on the library you're using, this is my own style:
ajax(url_to_template, function (request) {
var xml = request.responseXML;
var title = xml.getElementsByTagName('title');
if (title) {
insertion_point.innerHTML += substitute_strings(title[0],substitutions);
}
var body = xml.getElementsByTagName('body');
if (body) {
insertion_point.innerHTML += substitute_strings(body[0],substitutions);
}
var script = xml.getElementsByTagName('script');
if (script) {
eval(substitute_strings(script[0],substitutions));
}
});
}
function substitute_strings (str, substitutions) {
for (var n in substitutions) {
str.replace(n,substitutions[n]);
}
return str;
}
The way to call the template would be:
insertTemplate('http://path.to.my.template', myDiv, {
'$CONTENT$' : "The template's content",
'$DOCUMENT$' : "the document",
'$HIDE_MORE$' : 0
});
The $ sign for substituted strings is merely a convention, you may use % of # or whatever delimiters you prefer. It's just there to make the part to be substituted unambiguous.
One big advantage to using substitutions on the javascript side instead of server side processing of the template is that this allows the template to be plain static files. The advantage of that (other than not having to write server side code) is that you can then set the caching policy for the template to be very aggressive so that the browser only needs to fetch the template the first time you load it. Subsequent use of the template would come from cache and would be very fast.
Also, this is a very simple example of the implementation to illustrate the mechanism. It's not what I'm using. You can modify this further to do things like multiple substitution, better handling of script block, handle multiple content blocks by using a for loop instead of just using the first element returned, properly handling HTML entities etc.
The reason I really like this is that the HTML is simply HTML in a plain text file. This avoids quoting hell and horrible string concatenation performance issues that you'll usually find if you directly embed HTML strings in javascript.
I think I found a solution I like.
I will store templates in files and fetch them using AJAX. This works for development stage only. For production stage, the developer has to run a compiler once that compiles all templates with the source files. It also compiles JavaScript and CSS to be more compact and it compiles them to a single file.
The biggest problem now is how to educate other developers doing that. I need to build it so that it is easy to do and understand why and what are they doing.
You could also use \n to generate newlines. The html would however be on a single line and difficult to edit. But if you generate the JS using PHP or something it might be an alternative
How do I parse URL parameters in JavaScript? (These are the parameters I would ordinarily call GET parameters or CGI parameters, but in this case the page is basically submitting to itself, not a server, so there is no GET request and definitely no CGI program.)
I've seen a number of routines on the net that I can copy, but I have no idea how robust any of them are. I'm used to other languages like Perl and Java where I can rely on an extremely well-tested and robust library that I know will handle millions of little edge-cases in the standard. I would like the same here, rather than just cutting and pasting an example.
jQuery URL Utils or jQuery URL Parser.
Here's are two simple functions that do the job : http://adamv.com/dev/javascript/querystring
Here is a sample of the API Reference :
var qs = new Querystring();
// Parse a given querystring
var qs2 = new Querystring("name1=value1&name2=value2");
var v1 = qs2.get("name1");
var v3 = qs2.get("name3", "default value");
If it's "submitting to itself," do you need to do GET parameters?
But if you do, most browsers now have the decodeURIComponent function which will handle individual parameters; your job is to split them on & (String#split will do that nicely). If you want a library, jQuery and Prototype are both well-used and tested.
The best way I have found is to simply do it yourself and funnel the params into a global key/value object.
Getting quer params is simple...
just take a couple of .split()'s
var myquery = thewholeurl.split("?")[1]; //will get the whole querystring with the ?
then you can do a
myparams = myquery.split("&")
then you can do
for each param in myparams
{
temp = param.split("=");
mykeys.push(temp[0]);
myvalues.push(temp[1]);
OR
myObject[temp[0]] = temp[1];
}
It's just a matter of style.
This is not perfect code, just psuedo stuff to give you the idea.
I use the parseUri library available here:
http://stevenlevithan.com/demo/parseuri/js/
It allows you to do exactly what you are asking for:
var uri = 'http://google.com/?q=stackoverflow';
var q = uri.queryKey['q'];
// q = 'stackoverflow'
I've been using it for a while so far and haven't had any problems.
I found this useful for simple url parsing, modifying url (like adding new query params): https://github.com/derek-watson/jsUri
I think this library would work quite well, it is independent so you can use it with JQuery or with YAHOO or Dojo, another advantage is that it is pretty well documented.
http://www.openjsan.org/doc/t/th/theory/HTTP/Query/0.03/lib/HTTP/Query.html
You can use HTTP.Query to do all of the work for you in this case. It is only like 1.2 KB compressed so you could even include it in a bigger library if you wanted.
I recommend query-string library
Installing:
npm install query-string
Usage:
import queryString from 'query-string';
console.log(location.search);
//=> '?foo=bar'
const parsed = queryString.parse(location.search);
console.log(parsed);
//=> {foo: 'bar'}
parsed.foo = 'unicorn';
parsed.ilike = 'pizza';
const stringified = queryString.stringify(parsed);
//=> 'foo=unicorn&ilike=pizza'
location.search = stringified;
// note that `location.search` automatically prepends a question mark
console.log(location.search);
//=> '?foo=unicorn&ilike=pizza'
https://www.npmjs.com/package/query-string
Javascript has no built in support for URL parameters.
Anyway, the location.search property returns the portion of current page URL starting from the question mark ('?').
From this, you can write your own parameter parser or you can make use of one of those available in most common Javascript frameworks, such as JQuery and similar.