How to insert HTML inside template literal strings? - html

In React, I want to be able to use style words within a string which is defined in a variable using template literals.
For that I am making use of a to just style that word.
I am getting HTMLIntrinsic usage error.
Note- Solutions given in SO to questions related to this does not solve the issue I have. Pls check the code.
How to circumvent this problem
Tried using dangerouslyinsertHTML, but not a recommended solution.
//Actual code
const temperature = "22";
const list = {
item: `The temperature is ${temperature}`
}
//To style it-
const temperature = "22";
const list = {
item: `The temperature is <span style={{color:'red'}}>${temperature}</span>`
}
//And the above list.item is inserted inside JSX like -
return (
<div>{list.item}</div>
)
The temperature(22) needs to be styled.

Instead of the template string, you can use JSX elements for generating HTML as usual, placed next to your text elements. Example:
item: (
<>
The temperature is
<span style={{color:'red'}}>
{temperature}
</span>
</>
)
I'm using a Fragment to wrap the text and elements together, but you can use something else like a div if you wish to style the wrapper too.

You can't use React in template-literal like that because the React component is an object. Using it with template-literal will result in this[object Object] . So I recommend use other way, for example the solution by #richardo

You can make this as simple as this, IF you are OK to not have object like you defined
return(
<div>The temperature is <span style={{color: 'red'}}>{temperature}</span></div>
)

Related

Apply CSS only for number in React

If I have JSX like
<div>Hello there are 123 oranges</div>
Here's how text is set.
const Component = ({text}) => {
return(
<div>{text}</div>
)
}
I wanna make 123 red color. However, the text inside div is dynamic, so I can't insert span by hardcoding. Hopefully CSS can detect numeric but I couldn't find one by googling.
Are there any good and concise solutions?
It 's possible with dangerouslySetInnerHTML, you need regex to match the numeric part from your dynamic string and then generate the updated string with a style wrapped around that numeric part.
const yourText = yourText.replace(/\d+/, m => `<span style="color: red">${m}</span>` );
then pass this to dangerouslySetInnerHTML.
<div dangerouslySetInnerHTML={{__html: yourText}}></div>
You can perhaps try with regex
text.replaceAll(/(\d+)/g,'<span className="num">$1</span>')
String.prototype.replaceAll is an ES10 method.

SwiftSoup - Extracting specific div tags/elements

I'm not the most knowledgeable when dealing with scraping/getting data from a website, so apologies in advance. I have loaded in the HTML file locally, into my project so that I can have a reference and breakdown of the elements:
<div class="price">99</div>
<div class="size">M</div>
I want to select both these div classes, name and price and extract the value(s) which are 99 and M accordingly, how can I do this? I looked at SwiftSoups
let elements = try doc.select("[name=transaction_id]") // query
let transaction_id = try elements.get(0) // select first element
let value = try transaction_id.val() // get value
But that gave me an error. I can see you can select <P> tags, which are paragraphs, but how do I select the specific div class?
Once again, apologies if this is a beginner question.
Thank you.
Edit - The data I wish to parse:
var pstats = {att1:85,att2:92,att3:91,att4:95,att5:38,att6:65,acceleration:91,agility:91,balance:95,jumping:68,reactions:94,sprintspeed:80,stamina:72,strength:69,aggression:44,positioning:93,tactaware:40,vision:95,ballcontrol:96,crossing:85,curve:93,dribbling:96,finishing:95,fkacc:94,headingacc:70,longpass:91,longshot:94,marking:32,penalties:75,shortpass:91,shotpower:86,slidetackle:24,standingtackle:35,volleys:88,composure:96};
Edit 2 - New data I want to parse:
<div style="display: none;" id="player_stats_json">{"test":0,"ppace":85,"pshooting":92,"ppassing":91,"pdribbling":95,"pdefending":38,"pphysical":65,"acceleration":91,"sprintspeed":80,"agility":91,"balance":95,"reactions":94,"ballcontrol":96,"dribbling":96,"positioning":93,"finishing":95,"shotpower":86,"longshotsaccuracy":94,"volleys":88,"penalties":75,"interceptions":40,"headingaccuracy":70,"marking":32,"standingtackle":35,"slidingtackle":24,"vision":95,"crossing":85,"freekickaccuracy":94,"shortpassing":91,"longpassing":91,"curve":93,"jumping":68,"stamina":72,"strength":69,"aggression":44,"composure":96}</div>
If these tags have unique classes you can use getElementsByClass(_:) function and then get the first item, like this:
let price = try doc.getElementsByClass("price").first()?.text()
let size = try doc.getElementsByClass("size").first()?.text()

Rendering div that match array parameters

I have an issue rendering parameters in Angular 8, I get datas from API that I need to render in divs that matchs those datas but I'm having an issue where the datas shows in every divs, here's what it looks like :
Here, "Drops","Misc","Network" are the main divs that need to render the lower-categories.
Altought, what I want is for example, to have only "Drops Aluminium" inside the main "Drops", only "VANNE" inside "Misc" and "Main" in "Network". The lower categories should only renders when they have their ids inside the main id ( see picture 2 below ).
What I have tried :
Binding the values inside the divs, since all main and lower categories have ids like so :
Here is a stackblitz example : https://stackblitz.com/edit/angular-me2ppb?file=src%2Fapp%2Fapp.component.ts
Thank you in advance for your time and help, it's much appreciated !
If I understand correctly, could you just solve it with a nested loop in the template?
<div *ngFor="let main of total_by_level | keyvalue">
{{label_name[main.key]}}
<div *ngFor="let sub of main.value | keyvalue">
{{label_name[sub.key]}}
</div>
</div>
This would result in:
Network
Main
Drops
Drops Aluminium
Misc
VANNE
You have 2 options here:
Adapt your HTML to loop around total_by_level and query label_name appropriately
Build the output in code
It looks like you have attempted both, and so are open to either. Personally, I prefer to do as much as possible in the code and keep the HTML as dumb as possible, so I would take approach 2.
In ngOnInit() (which should be where you do any initial processing), I would build an array based on the structure on total_by_level.
output: any[];
ngOnInit() {
this.output = Object.keys(this.total_by_level).map(levelKey => {
const child = this.total_by_level[levelKey];
return {
level: {
label: this.label_name[levelKey]
},
children: Object.keys(child).map(childKey => ({
label: this.label_name[childKey],
value: child[childKey]
}))
};
});
}
It then becomes simple to bind to this array in your HTML:
<div *ngFor="let item of output">
{{item.level.label}}
<div *ngFor="let child of item.children">
{{child.label}}
{{child.value}}
</div>
</div>
You are dealing with some odd data structures, and I'm not sure of your terminology, so I have guessed a little bit here. You can take the concept of this idea and work with it. I am also assuming that there is only ever 1 nested child in total_by_level.
DEMO: https://stackblitz.com/edit/angular-upqdex

React: How to provide procedurally generated <li> elements distinct HTML id values?

I'm rendering a map of items retrieved from a database and filtered via the value state of an input field and attempting to then set the state of the input field as the value stored in some list item on click. I figured that using document.getElementById().innerHTML would allow me to retrieve the content stored within the appropriate tag and then set it to state which does work, the issue I'm facing is that it will only retrieve the innerHTML of the first item rendered in the map.
I've tried solutions ranging from applying UUID to making the mapped content available to the window and transfering the state of the individual objects but each disparate solution only moves the value of the first item to state - any ideas?
Rendered Content:
window.filteredItems = this.state.items.filter(
(item) => {
return item.companyNameObj.toLowerCase().indexOf(this.state.search.toLowerCase()) !== -1;
}
);
<div className="fixed-width">
<div className="search-container">
<form>
<input type="text" name="search" className="search-bar" placeholder="Search: " onChange={this.handleChange} value={this.state.search} />
</form>
<ul className="search-results">
{window.filteredItems.map((item) => {
return (
<div className="distinct-result-container">
<li key={item.id}>
<div className="image-container">
<img src={item.imageObj} alt={item.companyNameObj + " logo."}/>
</div>
<div className="company-container">
<span onClick={this.stateTransfer}><h3 id={"ID"}>{item.companyNameObj}</h3></span>
<p>Owned by: {item.ownerNameObj}</p>
</div>
</li>
</div>
)
})}
</ul>
</div>
<Footer />
</div>
);
stateTransfer()
stateTransfer(id) {
var search = this.state.search;
var uniqueID = document.getElementById("ID").innerHTML;
this.setState({
search: uniqueID
});
}
The current content of stateTransfer() doesn't represent any significant attempts at approaching a solution to this issue, it's just the minimum required implementation to move the innerHTML content to the input fields value.
EDIT: I've further clarified on the task at hand and a potential solution in the comments below (which follow this), I'm just hoping someone is able to help me with the actual implementation.
#DILEEPTHOMAS The list is comprised of data pulled from a Firebase Realtime Database and is rendered via mapping the filteredList and a search query; that functoionality works fine - what I need is to be able to click the element of any distinct li and have the innerHTML (the text stored in that li's item.companyNameObj) be moved to the value of the input field (so users can navigate the search content with re-typing).
#JoshuaLink I can't necessarily configure the items of the list any
further as it's just data pulled from an external database - I believe
the appropriate solution is to somehow provide a unique HTML ID value
to each newly rendered li and have that selected ID moved to
stateTransfer() where it can be set as the input fields value, I'm
just struggling with the actual implementation of this.
EDIT 2: I've managed to figure out a solution to both parts of the problem as described above - I'll post it as an answer below.
I managed to solve both parts of my problem:
The key issue, which was moving the text stored in each distinct li to the input value, which was apparently easily solved by making my stateTransfer() function accept an event and passing the .innerText value of the h3 through the event (I assumed I would have to use .innerHTML, which would require me to provide each distinct li with a unique generated ID) as follows:
stateTransfer(e) {
var search = this.state.search;
var innerText = e.target.innerText
this.setState({
search: innerText
})
}
The secondary issue, (which I incorrectly assumed was integral to implementing a solution to my question), assigning unique HTML id values to my procedurally generated li's was solved by implementing a for-loop in a componentDidUpdate() function which iterates through the current total length of the list and and assigns an id with the loop iterator concatenated to the end of the string as follows:
componentDidUpdate() {
var i;
var searchCompanyNames = document.querySelectorAll('.comapnyNames');
for(i = 0; i < searchCompanyNames.length; i++) {
searchCompanyNames[i].id = 'companyName-' + i;
}
}
Whilst I didn't need to assign unique ID's to the li's in the correct implementation, it's a useful trick worth noting nonetheless.

How to retrieve specific data from html using XPath?

Hey guys I am having a hard time trying to get the stock price from a site using XPath.
the html is this:
<span class=" price">
<meta content="14.400" itemprop="price">
14.400
<span itemprop="priceCurrency"> BRL</span>
</span>
The path I used to retrieve the 14.400 value (all of them getting me null), were:
#"//span[#class=' price']";
#"/span[#class=' price']";
#"span[#class=' price']";
#"//meta[#itemprop='price'"];
#"/html/body/div[2]/div/div/div/div[2]/span/meta";
#"//html/body/div[2]/div/div/div/div[2]/span/meta";
After trying a lot more the closest I could get to what I need was using this xPath:
#"//span[#class=' price']/meta";
to get this log:
2014-02-07 13:50:39.616 manejoderisco[2838:60b] {
nodeAttributeArray = (
{
attributeName = itemprop;
nodeContent = price;
},
{
attributeName = content;
nodeContent = "14.280";
}
);
nodeName = meta;
}
But still returning me null value...
I finally managed to create the correct xPath which is this one:
#"//span/meta/#content
The HTML you are trying to parse isn't well formed, since there is no closing tag for meta.
However, if you are indeed able to catch the meta tag, you may want to select the content:
//span[#class=' price']/meta/#content
Or, if you need the first text field,
//span[#class=' price']//text()[1]
might work as well.
Don't forget that when you do //span/meta you are selecting the meta node, so <meta content="14.400" itemprop="price">14.400 (ending wherever, depending on what is using your xpath, since the HTML is malformed). If you want the content, you need to select either #content attribute or the text field with text().