I'm injecting html in my react component using dangerouslySetInnerHTML in a format like this :
<div
className="mt-2 col variant-attr-cell p-0"
dangerouslySetInnerHTML = { {
__html: JSON.parse(attrs[i].snippet).snippet.replace("{text}",
attrs[i].choices[j].visualization_data)
} }
>
</div>
and it works fine but I'm trying to pass style to the injected html at the same time but don't know how!
I'm trying to add different styles to the injected html based on the api I get, something like this:
height: 12px;
width: 12px;
border-radius: 50%;
display: inline-block;
margin: 0 4px;
FYI the injected html is something like this mostly:
<span></span>
and the styles must be added to this and not the container div!
Any solution is appreciated,
thanks.
You can still add the desired style. Just add another props style:
const styleObj = {
color: 'white',
backgroundColor: 'red'
};
<div
className="mt-2 col variant-attr-cell p-0"
dangerouslySetInnerHTML = {
{ __html: JSON.parse(attrs[i].snippet).snippet
.replace("{text}", attrs[i].choices[j].visualization_data)
}
}
style={styleObj}
>
</div>
If you're trying to add style inside the element that resides in the html, then you should have their styles there in the html itself.
I managed to do this by adding a ref to the container and using the useLayoutEffect hook.
const elRef = useRef();
useLayoutEffect(()=>{
if (elRef.current){
elRef.current.firstElementChild.style.height = '12px';
// set other style attributes
...
}
});
return <div
ref={elRef}
dangerouslySetInnerHTML={yourHTML}
/>
This assumes you only want to style the first child of your container, but you could use a similar approach for multiple children.
Since I get the HTML from API, I set the style attribute for the HTML with a static value in the database and replaced the static value from API in my component!
You can easily style element in dangerousHTML like this style='background-color:red' instead style={{backgroundColor:'red'}}
Related
I have this page like image below:
The filter has a dynamic width and is an external angular component
the table is inside the "parent" component
FYI:
The table component has a [height]="something" that accepts either string or number as parameters.
The table is a pivot table using a custom component called Dev-Extreme
All i want is to assign a value inside the [height]="" in the HTML component page that is dynamic so that the height of the table resizes based on how much space there is left in the page.
Could also use TypeScript to do that and maybe calculate the height each components takes in the page except the table and do calculations on that.
Can anyone help me here, i've been stuck on this for two hours.
You could use some css for what you need.
Use display: flex to distribute the sections as you need (top section fixed and bottom section with dynamic height).
And use overflow: auto to set the scroll in the table container only.
Example:
https://codepen.io/bcngr/pen/wvXdWBE
<div class="main">
<div class="filters-container">
<span>Filters</span>
</div>
<div class="table-container">
<div class="table">
<span>Table</span>
</div>
</div>
</div>
html, body {
padding: 0;
margin: 0;
}
.main {
height: 100vh;
display: flex;
flex-direction: column;
}
.filters-container {
background-color: #edf2f4;
height: 100px;
}
.table-container {
flex: 1;
overflow: auto;
}
.table {
background-image: linear-gradient(#8d99ae, #2b2d42);
height: 600px
}
I found a solution to this here's what i did:
Creating a #ViewChild() to gather the div element in my .ts:
#ViewChild('pivotFilter', { static: false }) stickyHeader?: ElementRef;
Here:
The div has an id="pivotFilter"
Using ViewChild we can get the HTML element
Declaring getter to calculate table height:
get filterHeight() { return window.innerHeight - (this.stickyHeader?.nativeElement.offsetHeight + 88); }
Here:
window.innerHeight is the height of the page
this.stickyHeader?.nativeElement.offsetHeight is the height of my component
That + 88 is the rest of the page height (the title, and the space between filter and table)
I had to run change detection on content initialization to prevent errors like so:
ngAfterContentInit(): void {
this.cd.detectChanges();
}
Then i just applied the height to the html page.
Hope this helps someone, cheers !
I was looking at styled-components and I saw this syntax:
const Title = styled.h1`
font-size: 1.5em;
text-align: center;
color: palevioletred;
`;
I can't understand what is going on under the hood and what property is actually applied to the styled object.
Is there anyone that can explain to me how this code even runs?
Read about tagged templates
This is basically a function, but you can run it without ()
const styled = data => {
return data + ' JavaScript';
};
const data = styled `I love`;
console.log(data);
Examples with built-in functions:
console.log('a b c'.split ` `)
console.log(Object.entries `abc`)
console.log([1, 2, 3].concat `abc`)
You create styled h1 element, for example in Header component :
const Title = styled.h1`
font-size: 2rem;
text-align: center;
color: blue;
`;
You use it like a <h1> tag but with custom name:
<Title>My portfolio</Title>
You finally get the static hash class name sc-<hashedStringName> and one is dynamic class:
<h1 class="sc-gsnERi fiwDZi">My portfolio</h1>
So styled-components:
generate static class name
generate dynamic class name
This basically allows you to create Custom Tag in JSX.
You can also pass props to the styling properties in styled-components.
If you have this jsx:
<Title>This is Custom H1</Title>
const Title = styled.h1`
color: red;
`
It will render HTML like this:
<h1 class="someRandomAlphabet">This is Custom H1</h1>
where the class of h1 tag will have these properties:
.someRandomAlphabet{
color: red;
}
I have some accordions from PrimeReact which I use in my code. But there are pictures inside and I want to make them smaller. This is the current problem:
As you can see, the picture is way too big. I want to set the width to 100%.
Now I did this already before when I used Angular with PrimeNG (same library, just for Angular) and I managed to this in the css file like:
:host ::ng-deep .p-accordion-content img {
width: 100%;
}
This code did exactly what I wanted.
Now I need the same for React. But it is not working when I use:
:host .p-accordion-content img {
width: 100%;
}
This is the code I used to create the accordions. Maybe it will help:
createAccordions = () => {
const allFAQs = this.state.allFAQs;
let accordions = [];
for (const faq of allFAQs) {
const accordion = <AccordionTab key={faq.uuid} header={faq.question}><div dangerouslySetInnerHTML={{ __html: faq.answer }}></div></AccordionTab>;
accordions.push(accordion);
}
return accordions;
}
render() {
return (
<div>
<div className="p-grid">
<div className="p-col-3">
</div>
<div className="p-col-6">
<Accordion>
{this.createAccordions()}
</Accordion>
</div>
<div className="p-col-3">
</div>
</div>
</div>
)
}
Does anyone know what I did wrong? How can I style the picture inside the accordionTab?
Thanks for every help!
this is easy you just need to do some experiments with your image dimensions for example...
add height along with width(this is used in CSS with pure html similar can be used in your code also)
:host .p-accordion-content img {
width: 100%;
height: auto;
}
thankyou
I need to create a CSS class with media queries based on input image. The react script to create the css should look something like this:
const getBackgroungImageSet = (image) => {
return `.mycontainer {
background-image:url("${image}?mw=500"); // big image
}
#media(max-width: 768px){
.mycontainer {
background-image:url("${image}?mw=250"); // small image
}
}`;
}
Is it possible to add this class to the document in react?
Here's a way to add your styles via a style tag. The actual method is based on something shown in the docs for React Helmet. Which is a good way of getting your style tags to the document head instead of arbitrarily in the middle of the dom.
For the style tag, you need to use type="text/css" and use a string so that there aren't syntax errors due to CSS syntax not being valid in JSX.
function Example() {
return (
<div>
<span>This should be purple</span>
<br/>
<span>This should have a blue border</span>
<style type="text/css">{`
span {
color: purple;
}
span:nth-of-type(2){
color: inherit;
border: 2px solid blue;
}
`}</style>
</div>
);
}
ReactDOM.render(<Example />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<div id="root"/>
Given a div with contenteditable=true, how can I add text to the element?
<div aria-autocomplete="list" contenteditable="true" role="textbox" spellcheck="true">
</div>
I've tried document.activeElement.value, but since it's a div I can't set the value
With the other answers about innerHTML, I am afraid if innerHTML without sanitization might give attackers a chance to run unwanted malicious code.
I would rather go with textContent because the OP wants to add text.
HTML:
<div id="content" aria-autocomplete="list" contenteditable="true" role="textbox" spellcheck="true">
</div>
JAVASCRIPT:
document.getElementById('content').textContent = 'My text';
If you want to render HTML tags too you need a sanitization callback to filter tags like SCRIPT tag as an example.
You can just change the innerHTML of the div. So for example:
document.activeElement.innerHTML = "Changed text";
You can also get the current contents of the div by getting the same property, for example:
alert("User entered text: " + document.activeElement.innerHTML);
A React ref version answer of this question:
// set the init value to it
const initText = "123\n123123\n123123123";
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
if (ref && ref.current) {
ref.current.innerText = initText;
}
}, []);
const handleInput = (e: ChangeEvent<HTMLDivElement>) => {
console.log("input:", e.target.innerText);
};
notice that we are using innerText here,
for innerHtml, textContent they won't give a default line-change for \n with the code below
<div
ref={ref}
contentEditable={true}
onInput={handleInput}
style={{
height: 200,
width: 200,
border: "1px solid black",
display: "table-cell",
verticalAlign: "middle",
textAlign: "left",
padding: 8
}}
></div>
additionally, we can use CSS :empty to let the initial cursor keep at the vertical center as well
.InputField {
height: 200px; // initial height, real size could auto increase
...
}
.InputField:empty {
line-height: 200px; // the same initial height's value as above
}
I've found that the best way to set the content is:
target.firstChild.data = "<some-new-value>";
..where the firstChild is the textNode.