ES6 when to use String.raw over default template literal - javascript

I'm trying to concatenate a bunch of strings to build a query string in Javascript. Previously I have achieved this through ugly string concatenation:
var queryString = "?action=" + actionValue + "&data=" + dataValue";
But with ES6 I see that there are new methods provided that could help me achieve the same result with much nicer looking code, like string interpolation in C# 6:
string s = $"action={actionValue}&data={dataValue}"
I have tested with both default template literal and String.raw and although the syntax for each is slightly different, they both work. I'm leaning towards using String.raw in my final copy as it doesn't allow for the string to be tagged and thus tinkered with in the future like the default template literal does.
Although it does say in the MDN docs that String.raw basically calls the default template literal method but I like the syntax of String.raw better... I am calling the String.join method inside the curly braces of my string that I am formatting so maybe that is a misuse of String.raw.
Are any ES6 wizards out there able to enlighten me and provide reasons for one over the other?
My code:
var defaultTemplateStringUrl = `#Url.Action("DownloadMultiple")?inIds=${inData.join(',')}&outIds=${outData.join(',')}&truckId=${truckId}`;
var rawStringUrl = String.raw `#Url.Action("DownloadMultiple")?inIds=${inData.join(',')}&outIds=${outData.join(',')}&truckId=${truckId}`;
window.open( /*url goes here*/);

A template literal produces a string. If you use String.raw, you will get the raw form of that string:
`a\tb`; // "a b"
String.raw`a\tb`; // "a\tb"
So you should use String.raw only when you want the raw form.

No, using String.raw makes no sense for you.
You should rather write your own template tag that does the necessary URL encoding and handles arrays in a manner you like.
function myUrl(parts) {
var url = parts[0];
for (var i=1; i<arguments.length; i++) {
var val = arguments[i];
if (Array.isArray(val))
val = val.join(",");
url += encodeURIComponent(val);
url += parts[i];
}
return url;
}
Then you can use
window.open(myUrl`#Url.Action("DownloadMultiple")?inIds=${inData}&outIds=${outData}&truckId=${truckId}`);

Related

Treat String as JavaScript and output variables

Assume I have string '${hello} ${love} times'
I would like to replace hello by the variable named hello and love by the variable named love without removing times. I am using ReactJS with JSX.
My attempt is just removing the $, { and } from the string and then deal with it.
var cut = this.props.string.split(" ");
var one = cut[0].split("{");
var two = one[1].split("}");
var thin = this.var[two[0]];
and then use thin
Your question is completely unclear... Do you know how ES6 template literals work? You have to use backticks to enable string interpolation, not regular quotes ('' or "").
Is this what you are trying to do?
let hello = 'Hello',
love = 'LOVE';
console.log(`${hello} ${love} times`);

Escaping javascript entities in js?

I want to escape javascript entities on client side. For example :-
If my input string is tes"t result should be tes\"t
Is there any inbuilt function provided by jquery for this ?
This is a really crazy, almost stupid shot in the dark on my part, but...
If you're using a server-side language like PHP to output variables' contents into JavaScript, you should use json_encode as this handles ALL escaping for you, regardless of the type of variable.
On the other hand, if you're (I really hope you're not) doing something like this:
var input = "test"t";
And trying to escape that properly while in JavaScript... that's not going to work. It's a syntax error. You need to escape your literals manually.
Kevin van Zonneveld provide a JavaScript equivalent of PHP’s addslashes here :
http://phpjs.org/functions/addslashes/
function addslashes(str) {
// example 1: addslashes("kevin's birthday");
// returns 1: "kevin\\'s birthday"
return (str + '')
.replace(/[\\"']/g, '\\$&')
.replace(/\u0000/g, '\\0');
}
Based on this function, I guess you might want to add this function to prototype of the String like this.
if (!String.prototype.addslashes) {
String.prototype.addslashes = function () {
return this.replace(/[\\"']/g, '\\$&').replace(/\u0000/g, '\\0');
};
}
var str = 'tes"t';
alert(str.addslashes()); // shows 'tes\"t'
DEMO: http://jsfiddle.net/naokiota/6F6aN/6/
Hope this helps.

How to parse JSON that has inner layers using Javascript?

I can eval simple JSON with javascript.
var json = '{"amount":"50","id":"3"}';
var out = eval("{" + json + "}");
Now I am using JPA with REST and JSON-nized query result would include table name which makes
JSON having inner JSON so simple eval wouldn't work.
{"inventory":{"amount":"50","id":"3"}}
I've looked around the web for solution but can't find my case.
Should I just do string manipulation and extract {"amount":"50","id":"3"} part?
Or is there other way?
Yes, there is another (better) way! Use JSON.parse() to parse your JSON and get your object out:
var obj = JSON.parse(jsonString);
//then, for example...
var amount = obj.inventory.amount;
For older browsers (IE <8 for example) without native JSON support, include json2.js so this above still works.
Even this should work:
var json = '{"inventory":{"amount":"50","id":"3"}}';
var out = eval("{" + json + "}");
alert(out.inventory.amount);
But better to use JSON.parse
Aniway, I think that the proper way to perform a simple eval is to have the json string surrounded with parenthesis, not curly brackets...
var out = eval("(" + json + ")");
Cf. https://github.com/douglascrockford/JSON-js/blob/master/json.js :
// In the third stage we use the eval function to compile the text into a
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
// in JavaScript: it can begin a block or an object literal. We wrap the text
// in parens to eliminate the ambiguity.
j = eval('(' + text + ')');

javascript regex - remove a querystring variable if present

I need to rewrite a querysting using javascript.
First I check to see if the variable is present, if it is I want to replace it with a new search term. If it is not present then I just add the new variable
I'm able to get it to work with simple terms like hat, ufc hat
whitespaces are %20, so ufc hat is really ufc%20hat
I run into problem with terms like make-up, hat -baseball, coffee & tea, etc..
What is the proper regex for this?
Below is my code, which doesn't work.
var url = String(document.location).split('?');
querystring = url[1];
if(querystring.match(/gbn_keywords=/)!=null)
querystring=querystring.replace(/gbn_keywords=[a-zA-Z0-9%20.]+/,"gbn_keywords="+term);
else
querystring=querystring+"&gbn_keywords="+term;
No Regex needed. To get the query arguments, take everything after ?. Then, split the string by & to return each argument. Split again by = to get the arg name (right of =) and the value (left of =). Iterate through each argument, a rebuild the URL with each argument, excluding the one you don't want. You shouldn't run into problems here because ?, &, and - must be escaped if they are to be used in arguments. You also said you want to add the argument if it doesn't exist, so just set a variable to true, while you are iterating through each argument, if you find the argument. If you didn't append it to the end of the query string that you rebuilt.
location objects already have perfectly good properties like pathname, hostname etc. that give you the separate parts of a URL. Use the .search property instead of trying to hack the URL as a string (? may not only appear in that one place).
It's then a case of splitting on the & character (and maybe ; too if you want to be nice, as per HTML4 B2.2) and checking each parameter against the one you're looking for. For the general case this requires proper URL-decoding, as g%62n_keywords=... is a valid way of spelling the same parameter. On the way out naturally you will need to encode again, to stop & going on to the next parameter (as well as to include other invalid characters).
Here's a couple of utility functions you can use to cope with query string manipulation more easily. They convert between the ?... string as seen in location.search or link.search and a lookup Object mapping parameter names to arrays of values (since form-url-encoded queries can have multiple instances of the same parameter).
function queryToLookup(query) {
var lookup= {};
var params= query.slice(1).split(/[&;]/);
for (var i= 0; i<params.length; i++) {
var ix= params[i].indexOf('=');
if (ix!==-1) {
var name= decodeURIComponent(params[i].slice(0, ix));
var value= decodeURIComponent(params[i].slice(ix+1));
if (!(name in lookup))
lookup[name]= [];
lookup[name].push(value);
}
}
return lookup;
}
function lookupToQuery(lookup) {
var params= [];
for (var name in lookup)
for (var i= 0; i<lookup[name].length; i++)
params.push(encodeURIComponent(name)+'='+encodeURIComponent(lookup[name][i]));
return params.length===0? '' : '?'+params.join('&');
}
This makes the usage as simple as:
var lookup= queryToLookup(location.search);
lookup['gbn_keywords']= ['coffee & tea'];
var query= lookupToQuery(lookup);
& character is used to seperate key and value pairs in the querystring. So that you can match all the characters except for & by re-writing your code as follows:
querystring=querystring.replace(/gbn_keywords=[^&]+/,"gbn_keywords="+term);
[^&]+ matches one or more characters up to & or end of string. But if there may situations where the querystring data may look like ...?gbn_keywords= (no value) then a slight modification is needed to the above line:
querystring=querystring.replace(/gbn_keywords=[^&]*/,"gbn_keywords="+term);
Just change + to * so that the regex will match 0 or more characters. I think this is better.
Why don't you run a split on url[1] and than replace the value of the gbn_keywords in that new array?
And if you use a JavaScript Framework, there might be a handy function that does all that. In Prototype there is the function toQueryParams().

refactor HTML-generating JavaScript

Unfortunately on my project, we generate a lot of the HTML code in JavaScript like this:
var html = new StringBuffer();
html.append("<td class=\"gr-my-deals\">").append(deal.description).append("</td>");
I have 2 specific complaints about this:
The use of escaped double quotes (\”) within the HTML string. These should be replaced by single quotes (‘) to improve readability.
The use of .append() instead of the JavaScript string concatentation operator “+”
Applying both of these suggestions, produces the following equivalent line of code, which I consider to be much more readable:
var html = "<td class=’gr-my-deals’><a href=’" + deal.url + "’ target=’_blank’>" + deal.description + "</a></td>";
I'm now looking for a way to automatically transform the first line of code into the second. All I've come up with so far is to run the following find and replace over all our Javascript code:
Find: ).append(
Replace: +
This will convert the line of code shown above to:
html.append("<td class=\"gr-my-deals\">" + deal.description + "</td>)";
This should safely remove all but the first 'append()' statement. Unfortunately, I can't think of any safe way to automatically convert the escaped double-quotes to single quotes. Bear in mind that I can't simply do a find/replace because in some cases you actually do need to use escaped double-quotes. Typically, this is when you're generating HTML that includes nested JS, and that JS contains string parameters, e.g.
function makeLink(stringParam) {
var sb = new StringBuffer();
sb.append("<a href=\"JavaScript:myFunc('" + stringParam + "');\">");
}
My questions (finally) are:
Is there a better way to safely replace the calls to 'append()' with '+'
Is there any way to safely replace the escaped double quotes with single quotes, regex?
Cheers,
Don
Consider switching to a JavaScript template processor. They're generally fairly light-weight, and can dramatically improve the clarity of your code... as well as the performance, if you have a lot of re-use and choose one that precompiles templates.
Here is a stringFormat function that helps eliminate concatenation and ugly replacment values.
function stringFormat( str ) {
for( i = 0; i < arguments.length; i++ ) {
var r = new RegExp( '\\{' + ( i ) + '\\}','gm' );
str = str.replace( r, arguments[ i + 1 ] );
}
return str;
}
Use it like this:
var htmlMask = "<td class=’gr-my-deals’><a href=’{0}’ target=’_blank’>{1}</a></td>";
var x = stringFormat( htmlMask, deal.Url, deal.description );
As Shog9 implies, there are several good JavaScript templating engines out there. Here's an example of how you would use mine, jQuery Simple Templates:
var tmpl, vals, html;
tmpl = '<td class="gr-my-deals">';
tmpl += '#{text}';
tmpl += '</td>';
vals = {
href : 'http://example.com/example',
text : 'Click me!'
};
html = $.tmpl(tmpl, vals);
There is a good reason why you should be using the StringBuffer() instead of string concatenation in JavaScript. The StringBuffer() and its append() method use Array and Array's join() to bring the string together. If you have a significant number of partial strings you want to join, this is known to be a faster method of doing it.
Templating? Templating sucks! Here's the way I would write your code:
TD({ "class" : "gr-my-deals" },
A({ href : deal.url,
target : "_blank"},
deal.description ))
I use a 20-line library called DOMination, which I will send to anyone who asks, to support such code.
The advantages are manifold but some of the most obvious are:
legible, intuitive code
easy to learn and to write
compact code (no close-tags, just close-parentheses)
well-understood by JavaScript-aware editors, minifiers, and so on
resolves some browser-specific issues (like the difference between rowSpan and rowspan on IE)
integrates well with CSS
(Your example, BTW, highlights the only disadvantage of DOMination: any HTML attributes that are also JavaScript reserved words, class in this case, have to be quoted, lest bad things happen.)

Categories

Resources