I am new to this and learning react at the moment. So i made a custom gutenberg block with 2 repeater fields. 1 is for a name and the second is for a number.
Technically it works. The fields are repeating etc. But the output i want to realize isn't working or i dont get it.
So in the html i want that this block repeat it self but i dont know how. If i repeat it once, it works like a charm. When i want to repeat it dubble or more, the output gets under the older output:
1 Field
<div class="skills__skills" >
<div class="skills__skill">
<p>{ skillnameFields }</p>
<div class="container__bgcolor">
<div class="skills html progress__skill" style={{width:{ percentFields } }}>
<span>{ percentFields }</span>
</div>
</div>
</div>
</div>
When i want 2 fields this happends:
<div class="skills__skills" >
<div class="skills__skill">
<p>{ skillnameFields }</p>
<p>{ skillnameFields }</p>
<div class="container__bgcolor">
<div class="skills html progress__skill" style={{width:{ percentFields } }}>
<span>{ percentFields }</span>
<span>{ percentFields }</span>
</div>
</div>
</div>
</div>
How can i make it work that this happends:
<div class="skills__skills" >
<div class="skills__skill">
<p>{ skillnameFields }</p>
<div class="container__bgcolor">
<div class="skills html progress__skill" style={{width:{ percentFields } }}>
<span>{ percentFields }</span>
</div>
</div>
</div>
</div>
<div class="skills__skills" >
<div class="skills__skill">
<p>{ skillnameFields }</p>
<div class="container__bgcolor">
<div class="skills html progress__skill" style={{width:{ percentFields } }}>
<span>{ percentFields }</span>
</div>
</div>
</div>
</div>
Here is mine full code:
I hope some on can help me :)
/**
* BLOCK: project-drie
*
* Registering a basic block with Gutenberg.
* Simple block, renders and saves the same content without any interactivity.
*/
// Import CSS.
import './editor.scss';
import './style.scss';
// import components
import { useBlockProps, RichText, InnerBlocks, MediaUpload, InspectorControls, } from '@wordpress/block-editor';
const { __ } = wp.i18n; // Import __() from wp.i18n
const { registerBlockType } = wp.blocks; // Import registerBlockType() from wp.blocks
const { Button, IconButton, PanelBody, TextareaControl, TextControl } = wp.components;
const { Fragment } = wp.element;
/**
* Register: aa Gutenberg Block.
*
* Registers a new block provided a unique name and an object defining its
* behavior. Once registered, the block is made editor as an option to any
* editor interface where blocks are implemented.
*
* @link https://wordpress.org/gutenberg/handbook/block-api/
* @param {string} name Block name.
* @param {Object} settings Block settings.
* @return {?WPBlock} The block, if it has been successfully
* registered; otherwise `undefined`.
*/
registerBlockType( 'cgb/block-project-drie-skillbar', {
title: __( 'project-drie - Skill bar' ), // Block title.
icon: 'shield',
category: 'project drie',
supports: {
align: true,
},
keywords: [
__( 'project-drie — CGB skillbar' ),
__( 'skillbar' ),
__( 'skill-bar' ),
],
attributes: {
title: {
type: 'string',
source: 'text',
selector: 'figcaption',
},
subtitle: {
type: 'string',
source: 'text',
selector: '.my-content',
},
mediaID: {
type: 'number',
},
mediaURL: {
type: 'string',
source: 'attribute',
selector: 'img',
attribute: 'src',
},
skillname: {
type: 'array',
default: [],
},
percent: {
type: 'array',
default: [],
},
},
/**
* The edit function describes the structure of your block in the context of the editor.
* This represents what the editor will render when the block is used.
*
* The "edit" property must be a valid function.
*
* @link https://wordpress.org/gutenberg/handbook/block-api/block-edit-save/
*
* @param {Object} props Props.
* @returns {Mixed} JSX Component.
*/
edit: props => {
const { attributes: {title, subtitle, mediaID, mediaURL }, className, setAttributes } = props;
const onChangeTitle = title => { setAttributes ( { title } ) };
const onChangeSubtitle = subtitle => { setAttributes ( { subtitle } ) };
const onSelectImage = ( media ) => { setAttributes( { mediaURL: media.url, mediaID: media.id,} );};
const handleAddSkillname = () => {
const skillname = [ ...props.attributes.skillname ];
skillname.push( {
skill: '',
} );
props.setAttributes( { skillname } );
};
const handleAddPercent = () => {
const percent = [ ...props.attributes.percent ];
percent.push( {
percentage: '',
} );
props.setAttributes( { percent } );
};
const handleRemoveSkillname = ( index ) => {
const skillname = [ ...props.attributes.skillname ];
skillname.splice( index, 1 );
props.setAttributes( { skillname } );
};
const handleRemovePercent = ( index ) => {
const percent = [ ...props.attributes.percent ];
percent.splice( index, 1 );
props.setAttributes( { percent } );
};
const handleSkillnameChange = ( skill, index ) => {
const skillname = [ ...props.attributes.skillname ];
skillname[ index ].skill = skill;
props.setAttributes( { skillname } );
};
const handlePercentChange = ( percentage, index ) => {
const percent = [ ...props.attributes.percent ];
percent[ index ].percentage = percentage;
props.setAttributes( { percent } );
};
let skillnameFields,
skillnameDisplay;
let percentFields,
percentDisplay;
if ( props.attributes.skillname.length ) {
skillnameFields = props.attributes.skillname.map( ( skillname, index ) => {
return <Fragment key={ index }>
<TextControl
className="skillbar__react__name"
placeholder="Add Skill Name. Example: HTML"
value={ props.attributes.skillname[ index ].skill }
onChange={ ( skill ) => handleSkillnameChange( skill, index ) }
/>
<IconButton
className="skillbar__remove__react__name"
icon="no-alt"
label="Delete location"
onClick={ () => handleRemoveSkillname( index ) }
/>
</Fragment>;
} );
percentFields = props.attributes.percent.map( ( percent, index ) => {
return <Fragment key={ index }>
<TextControl
className="skillbar__react__percent"
placeholder="Add Percent Skill. Example: 50%"
value={ props.attributes.percent[ index ].percentage }
onChange={ ( percentage ) => handlePercentChange( percentage, index ) }
/>
<IconButton
className="skillbar__remove__react__percent"
icon="no-alt"
label="Delete location"
onClick={ () => handleRemovePercent( index ) }
/>
</Fragment>;
} );
skillnameDisplay = props.attributes.skillname.map( ( skillname, index ) => {
return <p key={ index }>{ skillname.skill }</p>;
} );
percentDisplay = props.attributes.percent.map( ( percent, index ) => {
return <p key={ index }>{ percent.percentage }</p>;
} );
}
return [
<div className={ className }>
<InspectorControls key="1">
<PanelBody title={ __( 'Skill Name' ) }>
{ skillnameFields }
<Button
isDefault
onClick={ handleAddSkillname.bind( this ) }
>
{ __( 'Add Name' ) }
</Button>
</PanelBody>
<PanelBody title={ __( 'Percent' ) }>
{ percentFields }
<Button
isDefault
onClick={ handleAddPercent.bind( this ) }
>
{ __( 'Add percent' ) }
</Button>
</PanelBody>
</InspectorControls>
<div key="2" className={ props.className }>
<div className="wp-block-cgb-block-project-drie-skillbar-repeater">
<div className="wp-block-cgb-block-project-drie-skillbar-repeater-title">
<p> Press on Skill bar</p>
<h2>Skill Bar</h2>
</div>
<div className="wp-block-cgb-block-project-drie-skillbar-skillname">
<h3>Skill Name</h3>{ skillnameDisplay }
</div>
<div className="wp-block-cgb-block-project-drie-skillbar-percentage">
<h3>percentage</h3>{ percentDisplay }
</div>
</div>
</div>
<div className="wp-block-cgb-block-project-drie-skillbar-info">
<div className="wp-block-cgb-block-project-drie-skillbar-title">
<h2>{ __('Title', 'cgb')}</h2>
<RichText
tagName="div"
className="wp-block-cgb-block-project-drie-skillbar-titles"
placeholder={ __('Add your title here', 'cgb')}
onChange={ onChangeTitle}
value={ title }
/>
</div>
<div className="wp-block-cgb-block-project-drie-skillbar-subtext">
<h2>{ __('Sub-Text', 'cgb')}</h2>
<RichText
tagName="p"
className="wp-block-cgb-block-project-drie-skillbar-subtexts"
value={ subtitle }
onChange={ onChangeSubtitle }
placeholder={ __('Add your sub-text here', 'cgb')}
/>
</div>
</div>
<div className="wp-block-cgb-block-project-drie-skillbar-bgimages">
<h2>Right Side Image</h2>
<div className="wp-block-cgb-block-project-drie-skillbar-bgimage">
<MediaUpload
onSelect={ onSelectImage }
allowedTypes="image"
value={ mediaID }
render={ ( { open } ) => (
<Button className={ mediaID ? 'image-button' : 'button button-large' } onClick={ open }>
{ ! mediaID ? __( 'Upload Image', 'gutenberg-examples' ) : <img src={ mediaURL } alt={ __( 'Upload Recipe Image', 'gutenberg-examples' ) } /> }
</Button>
) }
/>
</div>
</div>
</div>
];
},
/**
* The save function defines the way in which the different attributes should be combined
* into the final markup, which is then serialized by Gutenberg into post_content.
*
* The "save" property must be specified and must be a valid function.
*
* @link https://wordpress.org/gutenberg/handbook/block-api/block-edit-save/
*
* @param {Object} props Props.
* @returns {Mixed} JSX Frontend HTML.
*/
save: ( props ) => {
const {attributes: { title } } = props;
const {attributes: { subtitle } } = props;
const {attributes: { mediaURL} } = props;
const skillnameFields = props.attributes.skillname.map( ( skillname, index ) => {
return <p key={ index }>{ skillname.skill }</p>;
} );
const percentFields = props.attributes.percent.map( ( percent, index ) => {
return <p key={ index }>{ percent.percentage }</p>;
} );
return (
<section class="skills_bar">
<div class="container skills__container">
<div class="row skills__row">
<div class="skills__content">
<div class="skills__info col-md-6">
<div class="skills__text">
<div class="skills__title">
<h2>{ title } </h2>
</div>
<div class="skills__subtext">
<p>{ subtitle }</p>
</div>
</div>
<div class="skills__skills" >
<div class="skills__skill">
<p>{ skillnameFields }</p>
<div class="container__bgcolor">
<div class="skills html progress__skill" style={{width:{ percentFields } }}>
<span>{ percentFields }</span>
</div>
</div>
</div>
</div>
</div>
<div class="skills__images col-md-6">
<div class="skills__image">
<img src={ mediaURL}/>
</div>
</div>
</div>
</div>
</div>
</section>
);
},
} );