Material-UI CardContent not rendering the jump lines - reactjs

I have a component that renders a Material-UI Card, it receives a string like this:
'This
is
a
test'
But it renders 'This is a test' in one single line. I tried this:
<Card>
<CardContent>
<Typography noWrap>{value}</Typography>
</CardContent>
</Card>
and
<Card>
<CardContent>
{value}
</CardContent>
</Card>
both of them renders the value in a single line, however, if I console.log(value); then it shows the message as expected on the console.
How to overcome this?

You can use white-space: pre to force the text to go to the next line on newline character:
<Typography whiteSpace="pre">

Related

What is the best way to print this text with i18n?

Basically what I am trying to display is I am Python, Javascript and Flutter developer. string. But it looks this way:
With the following component in react:
<Typography gutterBottom variant="h6">
I am <HL>Python</HL>, <HL>Javascript</HL> and <HL>Flutter</HL> developer.
</Typography>
With HL component I basically am applying a few stylings to texts, how would I go translating that with next-translate? My best try is:
<Typography gutterBottom variant="h6">
{t("introduction2", {
langs: [
<HL>Python</HL>,
<HL>JavaScript</HL>,
<HL>Flutter</HL>,
]
})}
</Typography>
With:
{
...
"introduction2": "I am {{langs[0]}}, {{langs[1]}} and {{langs[2]}} developer.",
...
}
Also tried with:
{
...
"introduction2": "I am {{langs.0}}, {{langs.1}} and {{langs.2}} developer.",
...
}
And also tried with renderToString on HL components but it does not behave how you may expect as I use Next.JS to render the page, it messes up theme settings provided by mui.
EDIT
Solved it by using Trans component mentioned by #adrai, but the solution differed a bit so here is the last form:
import Trans from "next-translate/Trans";
...
<Typography gutterBottom variant="h6">
<Trans i18nKey="common:introduction2" components={[<HL />]}>
I am <HL>Python</HL>, <HL>Javascript</HL> and <HL>Flutter</HL> developer.
</Trans>
</Typography>
With:
{
...
"introduction2": "I am <0>Python</0>, <0>Javascript</0> and <0>Flutter</0> developer.",
...
}
Use the Trans Component: https://react.i18next.com/latest/trans-component
<Typography gutterBottom variant="h6">
<Trans i18nKey="myKey">I am <HL>Python</HL>, <HL>Javascript</HL> and <HL>Flutter</HL> developer.</Trans>
</Typography>
And in the translation string use the <1>Python</1> tagsā€¦
"myKey": "I am <1>Python</1>, <3>Javascript</3> and <5>Flutter</5> developer."

How to show a HTMLTag inside <CardHeader> Material UI Component

I am using React Material UI version 4.9.5 and React version 16.13.
Inside CardHeader tag i need to show 2 buttons. I tried placing buttons inside CardHeader tag but they dont show up. I placed the buttons inside title attribute of CardHeader but it shows buttons html code.
How to show HTML tag inside the CardHeader tag?
This is the part of code:
<div className={classes.root}>
<Card elevation={2} >
<CardHeader title= 'New Clin' className = {classes.cardHeaderClass}></CardHeader>
<CardContent className={classes.formContainer} >
<Divider className={classes.divider} />
<Grid container>
like in material ui card example, you need to add your button in action cardHeader props like for example:
<CardHeader
avatar={
<Avatar aria-label="recipe" className={classes.avatar}>
R
</Avatar>
}
action={
<IconButton aria-label="settings">
<MoreVertIcon />
</IconButton>
}
title="Shrimp and Chorizo Paella"
subheader="September 14, 2016"
/>

dynamically load an image as a prop in react

I am trying to load images dynamically in react and pass them as props. I have a data.json file that is basically an array of article objects.
title:"article1"
headline:"headline1"
image:"/src/images/articleimage1"
articleContent:"ipsum lorem"
in the first component I map through the array and return a "card" with props
const featuredArticles = imageCardArray.map(elem => <ImageCard
title={elem.title}
headline = {elem.headline}
image= {elem.image}
/>)
return (
<div className ="center">
{featuredArticles}
</div>
then I use those props in the card component itself. It all works perfectly except for the images
function ImageCard(props) {
return (
<div className="imageCard">
<Card>
<CardActionArea>
<CardMedia
component="img"
image={props.image}
title={props.title}
/>
<CardContent>
<Typography gutterBottom variant="h5" component="h2">
{props.title}
</Typography>
<Typography variant="body2" color="textSecondary" component="p">
{props.headline}
</Typography>
</CardContent>
</CardActionArea>
<CardActions>
<Button size="small" varient="outlined">
Artigo completo
</Button>
</CardActions>
</Card>
</div>
);
}
export default ImageCard;
any ideas how to load these images? the card component is from material UI if it helps. (it says in the docs that the image property just accepts a string)
I can get the image to load in the card by importing it at the top and then image = {image}, but of course then it is not dynamic and all the cards have the same image. please help!! thanks
You need to import the image from directory at top
import ArticleImg1 from 'image path';
and then construct your array of objects like this
{
title:"article1"
headline:"headline1"
image:ArticleImg1
articleContent:"ipsum lorem"
}
If I understand your question correctly it will work.
the answer is here https://medium.com/react-courses/5-top-methods-to-import-and-load-images-dynamically-on-cra-react-local-production-build-855d3ba3e704
you need to have in your json just the file name for the image, not the full path.
title:"article1"
headline:"headline1"
image:"articleimage1"
articleContent:"ipsum lorem
then in the card component:
you can either assign the resource to a component ...
const Image = require( '/src/images/'+ props.image);
and in the JSX
<img className="card-img-top" src={ Image } alt="image not found" />
or do the require in the jsx
<img className="card-img-top" src={ require( '/src/images/'+ props.image) } alt="image not found" />
assumption made that all images will be in the same folder...

Why is reat-admin not getting undefined exceptions for not-loaded record (e.g. Poster component)?

I am looking at react-admin demo code trying to learn from it. I have noticed quite a few time the same behavior: demo code is not waiting for a record to load and does not get undefined exceptions. I am struggling to understand why are they not getting the undefined exception. For example: In PosterEdit source code they are just using the component which looks like
const Poster = ({ record }) => {
const classes = useStyles();
return (
<Card className={classes.root}>
<CardContent className={classes.content}>
<img src={record.image} alt="" className={classes.img} />
</CardContent>
</Card>
);
};
If I use the component in the same way, I get undefined exception
TypeError: can't access property "image", record is undefined
I do not understand the magic from the demo code. Can someone demystify?
I found the answer for this exact example.
My Poster component was placed within several Grid components from material-u. Here is the cleaned code sample to show the structure.
<Edit {...props} aside={<Aside />}>
<TabbedForm }>
<FormTab >
<Grid container fullWidth className={classes.tabContent}>
<Grid item xs={7}>
<Grid container>
<Grid item xs={12}>
<Typography variant="h6" gutterBottom className={classes.sectionTitle}/>
<Poster
</Grid>
</Grid>
</Grid>
</Grid>
</FormTab >
..other form tabs..
</TabbedForm }>
</Edit>
If the component is placed directly as FormTab child, then it works. I still do not understand why though. Anyway, I hope it helps someone.

Typography in React Material-UI

I've this textbox:
<Typography component="p" className={classes.text}>
{this.props.post.text}
</Typography>
I'd like to be able to include paragraphs but all text entered into it gets printed on one line.
The documentation suggests that paragraph is defaulted to false so I must set it to `true.
I've tried the following:
<Typography component="p" className={classes.text} paragraph="true">
I also tried:
<Typography component="p" className={classes.text} paragraph={true}>
Neither work so all my text still gets printed to one line.
How do I get the paragraphs to show?
Additional info:
As I now understand, the paragraph={true} attribute in Typography just adds a bottom-margin to the whole text. I.E. my one block of text is a paragraph. If I want another paragraph I would have to add another Typography. Something like:
<Typography component="p" className={classes.text} paragraph={true}>
{this.props.post.text}
</Typography>
<Typography component="p" className={classes.text} paragraph={true}>
{this.props.post.text2}
</Typography>
This is not exactly what I want. Perhaps what I should be aiming for is to have the return characters in my input text recognised. Is this correct and if so, how is it done?
I tried this:
<pre>
<Typography component="p" className={classes.text}>
{this.props.post.text}
</Typography>
</pre>
The tag preservers the whitespace and line breaks inside the tags as is.
This is not suitable though. If I have long line the text does not wrap at the Card width. Instead anything beyond the width of the card becomes truncated. Clearly I want it all. I want my text to wrap in the card and also for it to support new lines and paragraphs. How is this done?
A better way is to use power of css:
white-space: pre-line
"New line" character will be respected if you use this css property.
Edit: Help from Ionut-Alexandru Baltariu
<Typography id="modal-description" sx={{ whiteSpace: 'pre-line'}}>
For new paragraphs
<Typography>
{this.props.text.split("\n").map((i, key) => {
return <p key={key}>{i}</p>;
})}
</Typography>
For just new lines
<Typography>
{this.props.text.split("\n").map((i, key) => {
return <div key={key}>{i}</div>;
})}
</Typography>
I tried your answer and it worked perfectly as needed. However, the console returns a minor error
Warning: validateDOMNesting(...): <p> cannot appear as a descendant
of <p>.
I improved on your answer slightly by replacing the <p> tags in your .map() with <Typography> and wrapping it all in a <div> instead, like so:
<div className={classes.text}>
{this.props.post.text.split('\n').map((i, key) => {
return <Typography key={key} paragraph variant="body1">{i}</Typography>;
})}
</div>
(you can replace body1 with whichever variant you want!)
This seems to get rid of the warning for me and I hope works as you intended.
I've come up with this:
<Typography component="p" className={classes.text}>
{this.props.post.text.split("\n").map((i, key) => {
return <p key={key}>{i}</p>;
})}
</Typography>
If there is a better way to do this I'd be keen to hear it.
This really is a strange behavior. From what I can tell, you are doing everything correctly. p is by itself displayed as block element so it should be by default displayed the way you want it to be. But, it could be that you are overriding that in your .text css class. Try to see if there is you problem. If not, you can always use variant property variant="headline" in order to put them on new lines.
If I get this right, you could simply leverage the power of HTML and add <br />-elements, to insert line-breaks.
This worked for me:
<Typography component="pre">
{this.props.post.text}
</Typography>
Starting in Material UI V5 you can now access many CSS utilities as props. For whitespace, you can now do:
<Typography whiteSpace="pre-line">{this.props.post.text}</Typography>

Resources