Javascript: How to use Template Literals with JSON? - javascript

I discovered Javascript ES6 Template Literals today. Just one word: Awesome!
Question: How to store and load Template Literals as JSON? I load some files via XHR, followed by some JSON.parse() which doesn't support ` instead of ", so it seems one can't save Template Literals directly in the files.
Goal: To use this for dynamic strings and translation and to get rid of confusing stuff like ("Hello " + username + "! How are you?") which requires multiple strings to be stored for just one message, and instead save my stuff beautifully and simple as
`Hello, ${username}! How are you?`
where username points to the dynamic variable with the same name. Is that possible? If yes, how to achieve this? It's okay if i have to use a function to somehow convert the strings into Template Literals as long as it doesn't hit hard on the overall performance, but I would like to at least avoid eval.

You can create your own function to parse template literal,
function stringTemplateParser(expression, valueObj) {
const templateMatcher = /{{\s?([^{}\s]*)\s?}}/g;
let text = expression.replace(templateMatcher, (substring, value, index) => {
value = valueObj[value];
return value;
});
return text
}
console.log(stringTemplateParser('my name is {{name}} and age is {{age}}', {name: 'Tom', age:100}));
// output 'my name is Tom and age is 100'

You could always use JSON.stringify to enclose dynamic data:
const data = 'some value';
JSON.stringify({
data,
});
// expected: "{\"data\": \"some value\"}"

I found it easier to separate the problem in a few substrings of JSON. Create the key "message" and this key stores parts of the message. It also works well for i18n.
{
"message" : {
"_0": "first part ",
"_1": "after first variable. ",
"_2": "after another variable"
}
}
And then, after decoding it, you can access it like
${message._0}${variable}${message._1}${var2}${message._2}

Try json-templates. Looks like exactly what you're looking for.

Related

Convert string array to array in javascript

I get the following item back from my django-rest-framework api call:
services = "['service1', 'service2', 'service3']"
I want services = ['service1', 'service2', 'service3']
In my JavaScript I tried services = JSON.parse(services)
- didn't do anything, also tried $.parseJSON(services).
In my serializers I have tried the setting services as ListField, also tried JSONSerializerField()
class JSONSerializerField(serializers.Field):
# Adapted from http://stackoverflow.com/a/28200902
def to_internal_value(self, data):
return json.loads(data)
def to_representation(self, value):
return value
To parse it you need to use double quotes instead of single.
This should work:
services = '["service1", "service2", "service3"]'
JSON.parse(services)
This is used to convert string which is array into pure array
var a = '[Aakash,akash]'
a.replace(/\[|\]/g,'').split(',')
(2) ["Aakash", "akash"]
Your response is of the form
services = "['service1', 'service2', 'service3']"
JSON.parse() will work if the parent quote is a single quote and all other child quotes are double quotes. I have quoted an example below
services = '["service1", "service2", "service3"]'
We can use replace() to achieve this
Here is a working example
services = "['service1', 'service2', 'service3']"
services = services.replace(/'/g, '"') //replacing all ' with "
services = JSON.parse(services)
console.log(services)
To ensure correct parsing between Django and some javascript browser code, be sure that you return a JsonResponse() in your controller. This ensures you can parse it with JSON.parse() in your Javascript.
Try Using:
var services = "['service1', 'service2', 'service3']"
services = services .split(",");
services [0] = services [0].substring(1);
services [services .length - 1] = services [services .length - 1].substring(
0,
services [services .length - 1].length - 1
);
services .forEach((x, i) => {
services [i] = services [i].includes('"') ? services [i].replaceAll('"', "").trim()
: services [i].replaceAll("'", "").trim();
});
console.log(services );
I recently found a roundabout way of solving a similar problem. I wanted to store an array as a data attribute in an HTML element so that I could use it later in the JS. However, such an HTML attribute could only be stored as a string. To solve this...
First I turned the arrays into a single string, with each value separated by a comma (ex. ["test 1", "test 2", "test 3"] is written as “test 1,test 2,test 3”).
Next, I entered the new string into the desired HTML data attribute. (ex. <div data-somedata="test 1,test 2,test 3"></div>)
Upon entering the JS, I retrieved that data string and converted it back into an array by using jQuery's "split” method. For this check out the snippet here.
let stillString = $("[data-something]").attr('data-something');
console.log(stillString);
let nowArray = stillString.split(",");
console.log(nowArray);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div data-something="test 1,test 2,test 3"></div>
This may not look pretty, keeping an array as a string, but it gets the job done and your average users won't know the difference.
NOTE: You don't HAVE to use commas. You could use any character really. The only thing that matters that none of the values that you're trying to separate contain the character that you chose split them with.

Dynamic replacement of values with regular expression

I have some data in the form
[
{
"name": "alex",
"fullname": "Alessandro Magno"
},
{
"name": "alex",
"fullname": "Alessandro Magno"
}
]
but (name and fullname) are not fixed, they may be "key"/"value", or whatever.
I'm also given a template to follow, e.g.:
var template = "<span>data.fullname (data.name)</span>".
My problem is the following:
I have to look for all the "data." in the string,
obtain the value following it (in this case, fullname and name),
and replace data. with my external source. E.g.
str.replace("data.<value>", source[value]);
In Javascript.
Thanks!
EDIT: I probably explained it wrongly. My source is defined (in this case, a name/fullname list in JSON format). I also have a template to follow. I have to replace the syntax used in the template (which is "data." ['data.' is fixed]) with the correspondent value of the source. Hope this is clearer now!
Re-thanks!
A simple replace call using a string will only replace a single instance of a substring. You'll have to use a regular expression.
Looking at what you're trying to do, I'd say you're probably looking for something like:
var s = "<span>data.fullname (data.name)</span>";
var replacements = {name: 'alex', fullname: 'alessandro'};//example
s.replace(/(data\.)([a-z]+)/g, function(a,b,c)
{
return b + (repl[c] || 'none');
});
This results in "data.alessandro (data.alex)"
How it works? Central to this approach is the regular expression:
/(data\.)([a-z]+)/g, which is quite basic:
(data\.): match and capture the literal string "data."
([a-z]+): again: match & capture 1 or more chars fater data. -> "data."
g: is the global flag, apply this patter to the entire string.
Now, for each match for this pattern that is found, instead of providing a replacement string, I provide a function, that is passed the matched substring (and the captured groups as separate arguments), and use the function construct a replacement string:
function(a, b, c)
{//a -> entire substring, b-> data., c-> string after data.
return b + (replacements[c] || 'none');// logical || to provide default string replacement
}
It's as simple as that, really. Given that your values are contained by objects, that are in an array, you could opt to code the following:
var vals = [{name: 'alex', fullname: 'alessandro'},{name: 'alex2', fullname: 'alessandro2'}],
results =[],
template = "<span>data.fullname (data.name)</span>";
for (var i=0;i<vals.length;++i)
results[i] = template.replace(/(data\.)([a-z]+)/g, function(a,b,c)
{
return b + (vals[i][c] || 'default');
});
Edit:
To remove data. substring, too, change the callback function (and pattern) to:
s.replace(/data\.([a-z]+)/function(a,c)
{
return replacements[c] || 'none';
});
In case of the code above:
for (var i=0;i<vals.length;++i)
results[i] = template.replace(/data\.([a-z]+)/g, function(a,c)
{
return vals[i][c] || 'default';
});
Is what you're after
If you need to use a template you could use template engine. Basically it will allow you to bind an object to a template. Behind the scene the template is parsed using regex. Pseudo-code:
var template = "<span>{fullname} ({name})</span>";
var html = template({ fullname: data.fullname, name: data.name });
To name a few:
http://handlebarsjs.com/
http://mustache.github.io/
http://underscorejs.org/
Underscore is more a library tool belt, but it provides a simple templating engine that works well for common use.
It is not clear what the transformation you are trying to achieve is, but I can tell you that you should not be using regex to achieve it! Transform your JSON into JavaScript objects using JSON.parse, transform the objects directly, then convert back to JSON via JSON.stringify.

Print JSON to screen for use with cut and paste

This is going to sound really ghetto, but I need to print some Javascript to the browser screen so that it can be cut and pasted into another program.
I'm using JSON.stringify() from json2.js, however, its not escaping characters such as quotes and new lines (",\n) which are actually control parts of a JSON object and need to be escaped.
For example, I'd get strings like this that cause problems when importing into the other program:
{
string_property_01 : "He said "HI""; // The string terminates after "He said "
}
Are there any libraries that I can use to escape all the characters that I need to escape here?
Thanks!
Option #2
var g = {
sampleFunc2 : function (data) {
var dataAsText = JSON.stringify(data);
// w jquery
$('#debugArea').text(dataAsText);
}
}
// usage...
g.sampleFunc2({ id: "4", name: "John Smith" });
In markup:
<textarea id='debugArea' rows='10' cols='50'></textarea>
I do the following, its a beautiful hack.
var g = {
sampleFunc : function (data) {
var dataAsText = JSON.stringify(data);
var response = prompt('you can copy and paste this', dataAsText);
}
}
// usage...
g.sampleFunc({ id: "4", name: "John Smith" });
JavaScript prompt... gotta love it.
Are you sure this isn't just a browser rendering thing playing tricks on you? A JSON library is going to escape chars properly to give you a valid JSON string. Have you tried comparing the output of json2.js to the native JSON.stringify some browsers (like chrome) have?

Replacing a property value in JSON

If I have a JSON structure that looks something like this:
var user = {
map: {
width: 785,
height: 791
},
image: {
name: "image.png",
size: {width:32}
},
properties:[{
firstName: "Bob",
lastName: "Jones",
}]
};
How would I change (after creation) the value of the firstName property to "Jane"?
I am fairly new to JSON, and I'm just trying to figure out how to make this one change for now. Any help would be greatly appreciated.
Well, one reason for your confusion might be that this is not JSON at all. JSON is a text format used for serialising objects. This is just a literal object in Javascript.
To change the firstName property, you would access the first item in the properties array in the user object:
user.properties[0].firstName = "Jane";
As long as the user variable is in scope:
user.properties[0].firstName = "Jane";
var changeName = function(obj, newName) {
obj.properties[0].firstName = newName;
return obj;
}
I saw this question and the solutions to it but my script still didn't work.
I found the solution and I figured I should post this here, it might save some people a little research.
My JSON result had some integers in it and it required the parseInt() function.
Taking the above example you probably have to do something like this.
user.map.width = parseInt(somevariable);
Since javascript is loosely typed I never really worry about it, but in this case it's necessary.

convert "converted" object string to JSON or Object

i've following problem and since i upgraded my prototypeJS framework.
the JSON parse is not able anymore to convert this string to an object.
"{empty: false, ip: true}"
previously in version 1.6 it was possible and now it needs to be a "validated" JSON string like
'{"empty": false, "ip": true}'
But how can i convert the 1st example back to an object?
JSON needs all keys to be quoted, so this:
"{empty: false, ip: true}"
is not a valid JSON. You need to preprocess it in order to be able to parse this JSON.
function preprocessJSON(str) {
return str.replace(/("(\\.|[^"])*"|'(\\.|[^'])*')|(\w+)\s*:/g,
function(all, string, strDouble, strSingle, jsonLabel) {
if (jsonLabel) {
return '"' + jsonLabel + '": ';
}
return all;
});
}
(Try on JSFiddle) It uses a simple regular expression to replace a word, followed by colon, with that word quoted inside double quotes. The regular expression will not quote the label inside other strings.
Then you can safely
data = JSON.parse(preprocessJSON(json));
It makes sense that the json parser didn't accept the first input as it is invalid json. What you are using in the first example is javascript object notation. It's possible to convert this to an object using the eval() function.
var str = "({empty: false, ip: true})";
var obj = eval(str);
You should of course only do this if you have the guarantees the code you'll be executing is save.
You can find more information about the json spec here. A json validator can be found here.
edit: Thai's answer above is probably a better solution
const dataWithQuotes = str.replace(/("(\\.|[^"])*"|'(\\.|[^'])*')|(\w+)\s*:/g, (all, string, strDouble, strSingle, jsonLabel) => {
if (jsonLabel) {
return `"${jsonLabel}": `;
}
return all;
});
return dataWithQuotes
similar solution as above , but updated with arrow functions.

Categories