is it possible to write a if statement in the return() from the save props in react?
Because when i write down a if statement i only see the code at the front-end.
So the following is happening:
I created a Selectcontrol:
<SelectControl
label={ __( 'Press ctrl to multiple stars:' ) }
value={ testimonial.selectcontrol } // e.g: value = [ 'a', 'c' ]
onChange={ (value) => handleTestimonialChange('selectcontrol', value, index ) }
options={ [
{ value: null, label: 'Select a Star', disabled: false },
{ value: 'star' , label: 'Add 1 star' },
{ value: 'star2', label: 'Add 2 stars' },
{ value: 'star3', label: 'Add 3 stars' },
{ value: 'star4', label: 'Add 4 stars' },
{ value: 'star5', label: 'Add 5 stars' },
] }
/>
I render it with the following code to have stars in the back-end:
selectcontrolDisplay = props.attributes.testimonial.map( ( testimonial, index ) => {
if (testimonial.selectcontrol == 'star') {
return (testimonial.selectcontrol == 'star') ? <span><i className="fas fa-star checked"></i></span> : testimonial.selectcontrol;
} else if (testimonial.selectcontrol == 'star2') {
return (testimonial.selectcontrol == 'star2') ? <span><i className="fas fa-star checked"></i><i className="fas fa-star checked"></i></span> : testimonial.selectcontrol;
} else if (testimonial.selectcontrol == 'star3') {
return (testimonial.selectcontrol == 'star3') ? <span><i className="fas fa-star checked"></i><i className="fas fa-star checked"></i><i className="fas fa-star checked"></i></span> : testimonial.selectcontrol;
} else if (testimonial.selectcontrol == 'star4') {
return (testimonial.selectcontrol == 'star4') ? <span><i className="fas fa-star checked"></i><i className="fas fa-star checked"></i><i className="fas fa-star checked"></i><i className="fas fa-star checked"></i></span>: testimonial.selectcontrol;
} else if (testimonial.selectcontrol == 'star5') {
return (testimonial.selectcontrol == 'star5') ? <span><i className="fas fa-star checked"></i><i className="fas fa-star checked"></i><i className="fas fa-star checked"></i><i className="fas fa-star checked"></i><i className="fas fa-star checked"></i></span> : testimonial.selectcontrol;
}
} );
In the editor part i have the following part:
{selectcontrolDisplay && selectcontrolDisplay.map((selectcontrolValue, i) =>
<div className="wp-block-cgb-block-project-drie-testimonial-ratings">
<div className="wp-block-cgb-block-project-drie-testimonial-rating">
<h2>Rating</h2>
{selectcontrolValue}
</div>
</div>
)}
So above is working correctly, but the hardest part for me is to get the result at the front-end.
So i thought i could make it work with a if statement. But i only see the code at the front-end and not the result with only stars. Could some on give me advice how to make this work?
save: ( props ) => {
const {attributes: { selectcontrol } } = props;
return (
html code.....
if (selectcontrol == 'star') {
<span><i className="fas fa-star checked"></i></span>
} else if (selectcontrol == 'star2') {
<span><i className="fas fa-star checked"></i><i className="fas fa-star checked"></i></span>
} else if (selectcontrol == 'star3') {
<span><i className="fas fa-star checked"></i><i className="fas fa-star checked"></i><i className="fas fa-star checked"></i></span>
} else if (selectcontrol == 'star4') {
<span><i className="fas fa-star checked"></i><i className="fas fa-star checked"></i><i className="fas fa-star checked"></i><i className="fas fa-star checked"></i></span>
} else if (selectcontrol == 'star5') {
<span><i className="fas fa-star checked"></i><i className="fas fa-star checked"></i><i className="fas fa-star checked"></i><i className="fas fa-star checked"></i><i className="fas fa-star checked"></i></span>
}
)
}
For a better overview:
save: ( props ) => {
const {attributes: { title } } = props;
const {attributes: { subtitle } } = props;
const {attributes: { media} } = props;
const {attributes: { testimonial } } = props;
const {attributes: { selectcontrol } } = props;
return (
<section className="testimonial">
<Helmet>
<script type="text/javascript" src="//cdn.jsdelivr.net/gh/kenwheeler/[email protected]/slick/slick.min.js"></script>
</Helmet>
<div className="container testimonial__container">
<div className="row testimonial__row">
<div className="testimonial__info">
<div className="testimonial__subtext">
<span>{ subtitle }</span>
</div>
<div className="testimonial__title">
<h2>{ title }</h2>
</div>
</div>
<div className="items testimonial__testimonials">
{testimonial.map((field, i) => (
<div className="testimonial__testimonial">
<div className="testimonial__card" key={ i }>
<div className="testimonial__image">
<img src={field.media.url} />
</div>
<div className="testimonial__review">
<p>{field.testimonial}</p>
</div>
if (selectcontrol == 'star') {
<span><i className="fas fa-star checked"></i></span>
} else if (selectcontrol == 'star2') {
<span><i className="fas fa-star checked"></i><i className="fas fa-star checked"></i></span>
} else if (selectcontrol == 'star3') {
<span><i className="fas fa-star checked"></i><i className="fas fa-star checked"></i><i className="fas fa-star checked"></i></span>
} else if (selectcontrol == 'star4') {
<span><i className="fas fa-star checked"></i><i className="fas fa-star checked"></i><i className="fas fa-star checked"></i><i className="fas fa-star checked"></i></span>
} else if (selectcontrol == 'star5') {
<span><i className="fas fa-star checked"></i><i className="fas fa-star checked"></i><i className="fas fa-star checked"></i><i className="fas fa-star checked"></i><i className="fas fa-star checked"></i></span>
}
<div className="testimonial__stars">
<span>{testimonial.selectcontrol}</span>
</div>
<div className="testimonial__author">
<div className="testimonial__name">
<span>{ field.author }</span>
</div>
<div className="testimonial__function">
<span>{ field.position }</span>
</div>
</div>
</div>
</div>
))}
</div>
</div>
</div>
</section>
);
},
CodePudding user response:
Looking at your code, you've tried really hard to get the right markup to save your stars by using if/if else
statements. You can have conditional rendering statements, but for your code/objective of saving the right markup for the stars may I suggest another way..
In the Editor, you have a <SelectControl/>
for setting a "star rating", so we want to save the value of the star rating in the block attributes. So lets assume we have defined "starRating" in the blocks attributes, eg:
block.json
{
...
"attributes": {
"starRating": {
"type": "string",
"default": "1"
}
}
}
I've set a default of 1 so there is no need for a null option on the <SelectControl/>
There is alot going on in your Edit()
function to render your beautiful star icons, so I will focus on the bare minimum required in the <SelectControl/>
. By using a number, we now can use map and easily generate the required options labels & values:
edit.js
import { __ } from '@wordpress/i18n';
import { useBlockProps } from '@wordpress/block-editor';
import { SelectControl } from '@wordpress/components';
export default function Edit({ attributes, setAttributes }) {
const { starRating } = attributes;
const STARS = [1, 2, 3, 4, 5];
return (
<div {...useBlockProps()}>
<SelectControl
label={__('Set Star Rating')}
value={starRating}
options={STARS.map((number) => {
let label = '*'.repeat(number); // simple trick for number of stars
return {
label: label,
value: number
}
})}
onChange={(value) => setAttributes({ starRating: value })} />
</div>
);
}
Next, in save()
the correct markup can be generated using the saved value of "starRating" with the benefit of avoiding if
if/else
statements altogether:
save.js
import { useBlockProps } from '@wordpress/block-editor';
export default function save({ attributes }) {
const { starRating } = attributes;
return (
<div {...useBlockProps.save()}>
<span>
{[...Array(parseInt(starRating))].map((item, index) =>
<i key={index} className="fas fa-star checked"></i>
)}
</span>
</div>
);
}
Note: "key" is required by react - it will not appear in the saved content or frontend.
Suggestions: Given all the content in your block, you may soon find managing both edit()
and save()
consistency to be challenging. Try to focus on the specific feature your block does, in your case the "star rating". With all the other parts, eg testimonial title, testimonial subtext etc, I'd suggest creating a reusable block or block/post template so you can easily change the layout/formatting/order of block/class names in the future. Updating/migrating blocks can be quite challenging if you need to change what is saved - if you can avoid having to do this, future you will thank you!