Replace Curly Braces in string with a HTML span Node in JSX - javascript

I have a string I need to parameterise like 'Hello {name}, how are you?'. I want to replace the curly braces and text inside with a variable then render it in my React Component but I also need that text to be highlighted and bold by wrapping the variable text in a span/strong tag e.g. of desired final result
Hello <span class="text-info"><strong>Dave</strong></span>, how are you?
I'm using React/JSX and I know how to replace the curly braces and text inside them using String.replace then render it e.g.
// This string with the placeholder curly braces would be received from an API call to a server. Only set here for demonstrative purposes
let string = 'Hello {name}, how are you?'
let name = 'Dave' // Likewise would not be set manually here, it's held in a redux store
let greeting = string.replace(/{(.*?)}/, name);
// This renders the greeting as you'd expect e.g. <p>Hello Dave, how are you?</p>
return (
<p>{greeting}</p>
)
However, if I try and replace the curly braces with a span element it renders incorrectly with [object Object] instead of my parameter
// ...rest of stateless Component.jsx
let greeting = string.replace(/{(.*?)}/, <span>{name}</span>);
// This renders the HTML <p>Hello [object Object], how are you?</p>
return (
<p>{greeting}</p>
)
I think it must be something to do with React escaping something but to be honest that's a total guess. Any ideas how I can achieve the desired functionality?
JSFiddle: https://jsfiddle.net/ExoticChimp1990/o69ymt7q/

You can try replacing by a string containing raw html tags and then render your div using dangerouslySetInnerHTML.
var greeting = textToEnhance.replace(/{(.*?)}/, '<span>'+this.props.name+'</span>');
return <div dangerouslySetInnerHTML={{__html:greeting}}></div>;

BTW, you can use the formatting of ES6 e.g.
const name = "David";
const myHTML = `Hello ${name}, how are you?`;
Note: these are not single quotes, but ` symbols. This symbol called as "grave accent" character
I understand your templates come from a server, so you cannot directly use the method above.
However, using RegExp such as /\$\{(\w+?)\}/g (click to expirement with this RegExp) you can parse and iterate through all your variable names e.g.
var newString = templateString.replace(/(\$\{\w+?\})/g, function(match, p1, offset, str) {
var matches = /\$\{(\w+?)\}/.exec(p1);
var variableName = matches[1];
return variables[variableName]
?variables[variableName]
:console.error("Variable " + variableName + " is undefined in offset " + offset);
});
When variables is a predefined object containing your variables as key values pairs and templateString contains your template (optionally from a server).

The second argument you are using in string.replace is not correct. name variable inside curly braces means, a javascript object with name key and value as that in name variable.
let greeting = string.replace(/{(.*?)}/, '<span><strong>'+name+'</strong></span>');
I am sorry, as I didnt enter the string above as code, it ommited the tags. Now they must be visible.

Related

How to get text between two custom html tags in JavaScript?

I am wondering how I can get text between two custom html tags. Example:
const a = "Hello, <num>22</num>";
//And here i want to get only 22 (between these two tags <num></num>
//I've tried something like this:
const nr = a.match(/<num>(.*?)<\/num>/g);
console.log(nr);
//But as you can see, it will only output <num>22</num>
While you could just access the contents using something like innerHTML, to answer your question from an input string via regular expression, you could use the exec() function. This will return an array where the first element is the entire matched string <num>22</num>, and subsequent elements will correspond to the captured groups. So nr[1] will yield 22.
const a = "Hello, <num>22</num>";
const nr = /<num>(.*?)<\/num>/g.exec(a);
console.log(nr[1]);
Note that exec() is a function of RegExp, not String like match() is.
In addition to the provided answers you could also add the string to a new element and search for it normally, for example
const a = "Hello, <num>22</num>";
var wrapper = document.createElement("div");
wrapper.innerHTML = a;
var element = wrapper.getElementsByTagName("num")[0];
console.log(element.innerHTML);
This allows you to match without actually inserting the text into the DOM and allows you to avoid regex which is not safe when parsing html.
It's generally not recommended to parse (x)html using regex.
Just a quick snippet here that works in Chrome, it looks like you can run queries against custom tags and also use the textContent property to get to the inner text:
const customContent = document.querySelector('custom').textContent
console.log(`custom tag's content: ${ customContent }`)
const numContent = document.querySelector('num').textContent
console.log(`num tag's content: ${ numContent }`)
<custom>inner text</custom>
<num>some more inner text</num>

What is the purpose of template literals (backticks) following a function in ES6?

In GraphQL you can write something like this to define a query:
const USER_QUERY = gql`
{
user(id: 2) {
name
}
}
`
In styled components you can define a styled component like this:
const Button = styled.button`
background-color: papayawhip;
`
What is this syntax? I know with template literals you can sub in variables with this syntax: ${foo} but I have never seen this used. Any guidance would be appreciated.
These are tagged template literals. The part before the backpacks is a reference to a function that will be called to process the string.
The function is passed the variables (the ${} parts) as arguments as well as the pieces of the string that surround the variables broken into an array. The return value of the function becomes the value of the template. Because of this very generalized format, you can do almost anything with the function. Here's a quick and dirty example that takes the variables (gathered into an array for convenience), makes them uppercase, and puts them back in the string:
function upperV(strings, ...vars) {
/* make vars uppercase */
console.log("vars: ", vars) // an array of the passed in variables
console.log("strings:", strings) // the string parts
// put them together
return vars.reduce((str, v, i) => str + v.toUpperCase() + strings[i+1], strings[0]);
}
let adverb = "boldly"
let output = upperV`to ${adverb} split infinitives that no ${'man'} had split before...`;
console.log(output)
Template literals have an additional feature called tagged templates. That's what the prefix before the opening backtick is. The prefix is actually the name of a function - the function is passed the constant parts of the template strings and the interpolated values (stuff in the ${} sections) and can process the resulting string into whatever it wants (although generally another string, doesn't have to be).
See this page on MDN for more details on how tagged templates work.

How to split data with square brackets while declaring parameter in json

I am passing some data from js file to handler which in turn gets result from SP. I have a parameter like ID = abc[123]. but i have to pass only 123 as value to ID to SP.
This is how im declaring parameter in js
var parameters = JSON.stringify({
"ID": JSON.stringify(EditedID).replace(/]|[[]/g, '')
});
But i am getting error like invalid ID
Kindly help
Currently, you are replacing the regex with empty space, so it will return the result 'abc123'. What you actually need is getting the string inside the brackets. You can use the below code to do it.
var EditedID = "abc[123]"
var regex = /\[([^\[\]]*)\]/
var result = ""
match = JSON.stringify(EditedID).match(regex)
if (match != null) {
result = match[1]
}
"result = match[1]" means that it will assign the value inside the brackets to result. If you want the value with both brackets, use match[0].
I assume that your EditedID is an object and somehow it will need the method "JSON.stringify" to make it become String. If your EditedID is already a String, just replace the match value to make it simpler
match = EditedID.match(regex)
If there is not match, the code won't run into the if condition so the value of result will just be an empty String.

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`);

Make text content between specified HTML tags toUpperCase in React-Native

I want to make to uppercase the contents of specific HTML tags with plain JavaScript in a React-Native application.
Note: This is a React-Native application. There is no JS document, available, nor jQuery. Likewise, CSS text-transform: uppercase cannot be used because it will not be displayed in a web browser.
Let's say, there is the following HTML text:
<p>This is an <mytag>simple Example</mytag></p>
The content of the Tag <mytag> shall be transformed to uppercase:
<p>This is an <mytag>SIMPLE EXAMPLE</mytag></p>
I tried this code:
let regEx = storyText.match(/<mytag>(.*?)<\/mytag>/g)
if(regEx) storyText = regEx.map(function(val){
return val.toUpperCase();
});
But the map() function returns only the matched content instead of the whole string variable with the transformed part of <mytag>.
Also, the match() method will return null, if the tag wasn't found. So a fluent programming style like storyText.match().doSomething isn't possible.
Since there are more tags to transform, an approach where I can pass variables to the regex-pattern would be appreciated.
Any hints to solve this?
(This code is used in a React-Native-App with the react-native-html-view Plugin which doesn't support text-transform out of the box.)
Since it seems that document and DOM manipulation (e.g., i.e., through jQuery and native JS document functions) are off limits, I guess you do have to use regex.
Then why not just create a function that does a job like the above: looping through each tag and replacing it via regex?
var storyText = "your HTML in a string";
function tagsToUppercase(tags) {
for(tag in tags) {
let regex = new RegExp("(<" + tags[tag] + ">)([^<]+)(<\/" + tags[tag] + ">)", "g");
storyText = storyText.replace(regex, function(match, g1, g2, g3) {
return g1 + g2.toUpperCase() + g3;
});
}
}
// uppercase all <div>, <p>, <span> for example
tagsToUppercase(["div", "p", "span"]);
See it working on JSFiddle.
Also, although it probably doesn't apply to this case, (#Bergi urged me to remind you to) try to avoid using regular expressions to manipulate the DOM.
Edit, Updated
The content of the Tag < mytag > shall be transformed to uppercase:
<p>This is an <mytag>SIMPLE EXAMPLE</mytag></p>
You can use String.prototype.replace() with RegExp /(<mytag>)(.*?)(<\/mytag>)/g to create three capture groups, call .toUpperCase() on second capture group
let storyText = "<p>This is an <mytag>simple Example</mytag></p>";
let regEx = storyText.replace(/(<mytag>)(.*?)(<\/mytag>)/g
, function(val, p1, p2, p3) {
return p1 + p2.toUpperCase() + p3
});
console.log(regEx);
In general you shouldn't be parsing html with javascript. With that in mind, if this is what you truly need to do, then try something like this:
let story = '<p>smallcaps</p><h1>heading</h1><div>div</div><p>stuff</p>';
console.log( story.replace(/<(p|span|div)>([^<]*)<\/(p|span|div)>/ig,
(fullmatch, startag,content,endtag) => `<${startag}>${content.toUpperCase()}</${endtag}>` )
)
Consider the cases where you might have nested values, p inside a div, or an a or strong or em inside your p. For those cases this doesn't work.
Why not this way ?
$("mytag").text($("mytag").text().toUpperCase())
https://jsfiddle.net/gub61haL/

Categories

Resources