I have an array with <p> and <div> items and I'm trying to render them as HTML, but whenever I try to render it, the values just appear as plain code and not the normal paragraphs. So I have an array with let's say that this information:
<p>The first paragraph of this pinned topic will be visible as a welcome message to all new visitors on your homepage. It’s important!</p>
<p><strong>Edit this</strong> into a brief description of your community:</p>
And when it gets rendered in the page, it gets rendered as this instead of the paragraph that should be rendered it gets rendered as plain code:
this is how it renders
This is the code I've used for render:
useEffect(() => {
axios.get(`/api/get-post?id=${pid}`)
.then(res => setPostData(res.data))
.catch(err => console.log(err.response))
}, [])
console.log(postData?.post_stream?.posts[0]?.cooked)
return (
<div>
<div className={styles.containerPadding}>
<div className={styles.mainContainer}>
<div className={styles.blackLine}>
</div>
<div className={styles.titleContainer}>
<div>
<h1>{postData.title}</h1>
</div>
<div>
<h1></h1>
</div>
</div>
<div className={styles.postInformationContainer}>
<div>
</div>
<div>
<p>{postData?.post_stream?.posts[0]?.cooked}</p>
</div>
</div>
</div>
</div>
</div>
You can use dangerouslySetInnerHTML for converting your string data to HTML, but for safety (avoiding XSS attack), you should sanitize your HTML string before using dangerouslySetInnerHTML by DOMPurify
import DOMPurify from 'dompurify'
const sanitizedHtml = DOMPurify.sanitize(postData?.post_stream?.posts[0]?.cooked)
And then call it like this
dangerouslySetInnerHTML={{__html: sanitizedHtml}}
useEffect(() => {
axios.get(`/api/get-post?id=${pid}`)
.then(res => setPostData(res.data))
.catch(err => console.log(err.response))
}, [])
const sanitizedHtml = DOMPurify.sanitize(postData?.post_stream?.posts[0]?.cooked)
return (
<div>
<div className={styles.containerPadding}>
<div className={styles.mainContainer}>
<div className={styles.blackLine}>
</div>
<div className={styles.titleContainer}>
<div>
<h1>{postData.title}</h1>
</div>
<div>
<h1></h1>
</div>
</div>
<div className={styles.postInformationContainer}>
<div>
</div>
<div>
<p dangerouslySetInnerHTML={{__html: sanitizedHtml}}></p>
</div>
</div>
</div>
</div>
</div>
One side note, without HTML string sanitization, your HTML data can be interfered by some script injections which would harm your website or your system.
You can use html-react-parser package
This is how your code will look like
import parse from 'html-react-parser'
useEffect(() => {
axios.get(`/api/get-post?id=${pid}`)
.then(res => setPostData(res.data))
.catch(err => console.log(err.response))
}, [])
return (
<div>
<div className={styles.containerPadding}>
<div className={styles.mainContainer}>
<div className={styles.blackLine}>
</div>
<div className={styles.titleContainer}>
<div>
<h1>{postData.title}</h1>
</div>
<div>
<h1></h1>
</div>
</div>
<div className={styles.postInformationContainer}>
<div>
</div>
<div>
<p>{parse(postData?.post_stream?.posts[0]?.cooked)}</p>
</div>
</div>
</div>
</div>
</div>
You can use 'dangerouslySetInnerHTML' like everyone else.
And I need to register the tags to use.
import DOMPurify from 'dompurify';
<div
dangerouslySetInnerHTML={{
__html: DOMPurify.sanitize(
view_inner ?? '<div>Unable to get data.</div>',
{
FORCE_BODY: true,
ADD_TAGS: ['style'],
ADD_ATTR: ['target'],
ALLOWED_TAGS: [
'span',
'div',
'link',
'table',
'thead',
'tr',
'th',
'tbody',
'td',
],
},
),
}}
/>
Related
Using a database management tool (HeidiSQL) I can see that the content of an entry is storing returns (good):
MYSQL storing line breaks
However when I read the data on my front-end:
router.get('/story/:id', async (req, res) => {
try {
const getStory = await Story.findByPk(req.params.id, {
include: [
{
model: User,
attributes: ['username'],
},
],
});
const story = getStory.get({ plain: true });
res.render('story', {
story,
logged_in: req.session.logged_in,
});
} catch (err) {
res.status(500).json(err);
}
});
Rendered in Handlebars:
<div class="card">
<div class="card-content">
<p class="title">
{{story.title}}
</p>
<p class="content">
{{story.content}}
</p>
</div>
</div>
It eliminates the line-breaks:
no line-breaks
I'm wondering what I need to do to maintain the linebreaks.
I haven't tried modifying anything yet. I will try encapsulating the handlebars {{story.content}} in a string-literal to see if that does it.
So I found the answer - I needed to add a custom handlebars helper in the server.js
hbs.handlebars.registerHelper('breaklines', function(text) {
text = hbs.handlebars.Utils.escapeExpression(text);
text = text.replace(/(\r\n|\n|\r)/gm, '<br>');
return new hbs.handlebars.SafeString(text);
});
Then pass the content through the helper
<div class="card">
<div class="card-content">
<p class="title">
{{story.title}}
</p>
<p class="content">
{{breaklines story.content}}
</p>
</div>
</div>
I have a div that looks like this:
<div id="data" class="grid grid-cols-2">
</div>
and I have a function that can append in data div:
function loadStaticBar(data) {
let pl_name= `bar-${data.title.replace(/\s+/g, '-').toLowerCase()}`
$('#data').append(`
<div class="flex flex-col" id="${pl_name}-wrapper">
<div class="static barchart" id="${pl_name}-plot">
</div>
</div>
`)
}
The content of loadStaticBar(data) is a key and value it's a details for charts:
{id: 453, title: 'Bar Chart Example', select: 'bar-form', xtitle: 'Values', ytitle: 'Date', …}
Now, I'm trying to get all the IDs with the class static. I have tried:
$('#data').find('.static')
And I get S.fn.init [prevObject: S.fn.init(1)] inside of this are bunch of information. How can I get the IDs of the div that containing static class like this.
ids = [line-plot, bar-plot]
The answer to the updated question could be:
function loadStaticBar(data) {
let pl_name= `bar-${data.title.replace(/\s+/g, '-').toLowerCase()}`
$('#data').append(`
<div class="flex flex-col" id="${pl_name}-wrapper">
<div class="static barchart" id="${pl_name}-plot">
</div>
</div>
`)
}
const data={id: 453, title: 'Bar Chart Example', select: 'bar-form', xtitle: 'Values', ytitle: 'Date'};
$(function(){
loadStaticBar(data); // create the divs first !!!
const ids=$("#data .static").get().map(el=>el.id);
console.log(ids);
});
<script src="https://code.jquery.com/jquery-3.6.1.min.js"></script>
<div id="data" class="grid grid-cols-2">
</div>
As you want to receive a "proper" array instead of a jQuery object it makes sense to .get() the selected DOM elements first and then .map() them using the standard Array-method.
Incidentally, you can solve the originally posted question also without jQuery:
document.addEventListener("DOMContentLoaded", function () {
const ids=[...document.querySelectorAll("#data .static")].map(el=>el.id);
console.log(ids);
});
<div id="data" class="grid grid-cols-2">
<div class="flex flex-col" id="line-wrapper">
<div class="static linechart" id="line-plot">
</div>
</div>
<div class="flex flex-col" id="bar-wrapper">
<div class="static barchart" id="bar-plot">
</div>
</div>
</div>
I need to put 2 rows of text, the "API Name" and "Resource Name" to the left, and put another 2 rows of text, the "Service Name" and "Status" to the right.
like this
However, the result is not what I want. this is my result:
my code:
const ViewHeader = (props: ViewHeaderProps) => {
const {apiName, resourceName, serviceName, apiStatus, desc, rpcName, verb, uri} = props;
return (
<div className="view-api-header">
<span>
<div>{apiName}</div>
<div>{serviceName}</div>
</span>
<span>
<div>{resourceName}</div>
<div>{apiStatus}</div>
</span>
<div>
<span>{apiName}</span>
<span>{serviceName}</span>
</div>
<div>
<span>{resourceName}</span>
<span>{apiStatus}</span>
</div>
</div>
);
};
I'm new to html and react, is there anyway to format the 4 elements correctly?
I suppose the HTML code should be like this
<div style="clear: both">
<div style="float: left">{apiName}</div>
<div style="float: right">{serviceName}</div>
</div>
<div style="clear: both">
<div style="float: left">{resourceName}</div>
<div style="float: right">{apiStatus}</divstyle>
</div>
In my project I am receiving array from backend in that JSON object is ->
list=[{
deleted: false,
details:{
groupNumber: "123ddd",
insuranceName: "Blue Sheild insurance",
memberId: "12345",
payerId: "21212",
relationToSubscriber: null,
ssn: true,
subscriberDoB: "1991-01-01",
subscriberFirstName: "Payor A",
subscriberLastName: "Added",
subscriberMiddleName: "middle",
},
editStatus: "PENDING",
imageInfo: null,
tier: "PRIMARY",
},]
Passing data from parent component
<div className="insurance-sub-heading">Card detials</div>
{insuranceList.map((m, index) => (
<InsuranceList
key={index}
value={m}
index={index}
text={getInsuranceStatusText(m.editStatus)}
/>
))}
</div>
to child component
const{value}=props
return(
<div className="insurance-body">
<div className="insurance-icon-name">
<div className="drop-down-icon" onClick={() => openDrawer(index)}>
<img src={show.visible ? downArrow : rightArrow} />
</div>
<div className="name-bold">{value.details.insuranceName}</div>
</div>
<div className="insurance-icon-name">
<div className="insurance-status">{text}</div>
<div className="insurance-status-icon">
{getInsuranceStatus(value.editStatus)}
</div>
</div>
</div>
{show.visible && (
<div className="dropDown-container">
{!value.details.ssn && (
<React.Fragment>
<div className="text-container">
<div className="text-heading">Member / Subscriber ID</div>
<div className="text">{value.details.memberId}</div>
</div>
{/* {value.details.groupNumber.trim() !== '' && ( */}
<div className="text-container">
<div className="text-heading">Group number</div>
<div className="text">{value.detials.groupNumber}</div>
</div>
{/* )} */}
</React.Fragment>
)}
<div className="text-container">
<div className="text-heading">Subscriber name</div>
<div className="text">John (optional middle) Dee</div>
</div>
<div className="text-container">
<div className="text-heading">Subscriber date of birth</div>
<div className="text">04/12/2000</div>
</div>
<div className="text-container">
<div className="text-heading">Relationship to the patient</div>
<div className="text">Mother</div>
</div>
</div>
)}
)
Problem which I am facing is when Child component loads it gives error that value.detials.groupNumber is undefined, Although object is present inside the json object. By clicking button I can console the value.detials.groupNumber it prints the data but it is not displaying it on HTML side it shows Empty
Chances there's a list item without a groupNumber
Consider using conditional rendering like this
{value.detials.groupNumber &&
<div className="text">{value.detials.groupNumber}</div>
}
Note:
You have a typo on, it should be details, and not detials
I have the following issue:
I am building a web application, BackEnd in spring and FrontEnd in React.
Now I am adding a feature that shows how many products are in the cart while the client is clicking on "buy". The problem is that when I do a map to get the API in the dom tree, it seems like is duplicating the element.
Images:
Bug: "Carrinho ( )" is being duplicated
Note:
I am consuming two APIs
Code:
import React, { useEffect, useState } from 'react';
import {
Row,
CardBody,
Container,
} from 'reactstrap';
import api from '../../resources/api_produtos';
import apiCart from '../../resources/api_cart';
import axios from 'axios';
const Main = () =>{
const[product, setProduct] = useState([]);
const[cart, setCart] = useState([]);
const fetchData = () =>{
const productApi = api.get('');
const cartApi = apiCart.get('');
axios.all([productApi, cartApi]).then(
axios.spread((...allData) =>{
const allProductData = allData[0].data;
const allDataCart = allData[1].data;
setProduct(allProductData);
setCart(allDataCart);
console.log(allDataCart);
})
)
}
useEffect(() =>{
fetchData()
}, [])
return (
<div>
<div className="p-3 mb-2 bg-dark text-white d-flex justify-content-between">
<div>
<strong>Game Store</strong>
</div>
<div>
{cart.map(carrinho =>(
<div key={carrinho.id}>
<div>
Carrinho ( {carrinho.amount} ) HERE IS BEING DUPLICATED
</div>
</div>
))}
</div>
</div>
<Container>
<div className="jumbotron mt-3"><h1>Produtos</h1></div>
{product.map(produto => (
<div className="card mb-3">
<div key={produto.id}className="card-header d-flex justify-content-between">
<span>
Id: {produto.id}
</span>
<div>
<nav>
<form method="POST" action={"http://localhost:8080/comprar/" + produto.id}>
<input type="submit" className="btn btn-secondary" value="Comprar" ></input>
</form>
</nav>
</div>
</div>
<CardBody>
<Row>
<div className="col-12 col-sm-8 mb-3">
<div className="row">
<div key={produto.id}>
<div >
Nome: {produto.name}
</div>
<div >
Preço: R$ {produto.price}
</div>
</div>
</div>
</div>
<div className="col-12 col-md-4">
<figure key={produto.id}>
<img className="img-thumbnail"src={produto.image} />
</figure>
</div>
</Row>
</CardBody>
</div>
))}
</Container>
</div>
);
}
export default Main;
And this is how the API "Cart" looks like:
[{"amount":"7"},[{"id":12,"name":"Mortal Kombat XL","price":69.99,"score":150,"image":"https://images-americanas.b2w.io/produtos/01/00/offers/01/00/item/126077/6/126077695_1GG.png"},{"id":12,"name":"Mortal Kombat XL","price":69.99,"score":150,"image":"https://images-americanas.b2w.io/produtos/01/00/offers/01/00/item/126077/6/126077695_1GG.png"},{"id":12,"name":"Mortal Kombat XL","price":69.99,"score":150,"image":"https://images-americanas.b2w.io/produtos/01/00/offers/01/00/item/126077/6/126077695_1GG.png"},{"id":12,"name":"Mortal Kombat XL","price":69.99,"score":150,"image":"https://images-americanas.b2w.io/produtos/01/00/offers/01/00/item/126077/6/126077695_1GG.png"},{"id":12,"name":"Mortal Kombat XL","price":69.99,"score":150,"image":"https://images-americanas.b2w.io/produtos/01/00/offers/01/00/item/126077/6/126077695_1GG.png"},{"id":12,"name":"Mortal Kombat XL","price":69.99,"score":150,"image":"https://images-americanas.b2w.io/produtos/01/00/offers/01/00/item/126077/6/126077695_1GG.png"},{"id":12,"name":"Mortal Kombat XL","price":69.99,"score":150,"image":"https://images-americanas.b2w.io/produtos/01/00/offers/01/00/item/126077/6/126077695_1GG.png"}]]
How do I fix this duplication?
The problem is the response object from your cart API.
It's bad-formed, since your BE is returning an array which gives no sense since the response includes one single cart.
So, the map function iterate over an array, modifying its content by the callback, place them in a new array, and then returns it.
So essentially you are trying to modify the obj on the index 0, which is and obj with the "amount" field, and then, you are trying to map an array at index 1.
So you have to update your response from the BE, something like that:
{
"id": "cart_id",
"items": []
}
Which has more sense compared with yours. Note that since items is an array you don't need the "amount" field, you can access it with carrinho.items.length for instance. Then render it with
<div key={carrinho.id}>
<div>Carrinho ({carrinho.items.length})</div>
</div>