JavaScript for WordPress › Forums › Gutenberg Development › Toggle Control conditional
- This topic has 4 replies, 2 voices, and was last updated 4 years, 6 months ago by chrisdavies71.
-
AuthorPosts
-
April 4, 2020 at 4:47 am #139251chrisdavies71Participant
Hi Zac,
I am attempting to build a custom Bootstrap inspired carousel block. I want to build a number of controls into the block to either show/hide things like indicators, controls etc. I have this set up in the inspector and it is mostly working.
Where I am stuck is checking the state of the toggle and then outputting HTML based on that. I have put the code below but the workflow should be:
1. If an image is not present show the media upload, if there is an image show it – done
2. If an image is present and the toggle for controls is ‘true’ then add a block of HTMLHope that sort of makes sense. I have tried various bits and I can get the two separate bits to work but can not combine them properly.
Any pointers much appreciated
Chris
/** * Block dependencies */ import icon from './icon'; import './style.scss'; import './editor.scss'; /** * Internal block libraries */ const { __ } = wp.i18n; const { registerBlockType } = wp.blocks; const { InspectorControls, MediaUpload, MediaUploadCheck } = wp.blockEditor; const { PanelBody, PanelRow, FormToggle, Button, TextControl } = wp.components; const { Fragment } = wp.element; /** * Register block */ export default registerBlockType( 'elecwork/carousel', { title: __( 'Carousel', 'elecwork' ), description: __( 'A Bootstrap inspired carousel complete with indicators, controls and ability to link to a page.', 'elecwork' ), category: 'common', icon: { src: icon, }, attributes: { carouselIndicators: { type: 'boolean', default: false, }, carouselControls: { type: 'boolean', default: false, }, carouselInterval: { type: 'string', }, imgURL: { type: 'string', source: 'attribute', attribute: 'src', selector: 'img', }, imgID: { type: 'number', }, imgAlt: { type: 'string', source: 'attribute', attribute: 'alt', selector: 'img', } }, keywords: [ __( 'Carousel', 'elecwork' ), __( 'Slider', 'elecwork' ), ], edit: props => { const { attributes: { carouselIndicators, carouselControls, carouselInterval, imgURL, imgID, imgAlt }, attributes, className, isSelected, setAttributes } = props; const toggleIndicators = () => setAttributes( { carouselIndicators: ! carouselIndicators } ); const toggleControls = () => setAttributes( { carouselControls: ! carouselControls } ); const onSelectImage = img => { setAttributes( { imgID: img.id, imgURL: img.url, imgAlt: img.alt, } ); console.log(img) }; return [ <InspectorControls> <PanelBody title={ __( 'Settings', 'elecwork' ) } > <PanelRow> <label htmlFor="carousel-indicators-form-toggle" > { __( 'Show Indicators', 'elecwork' ) } </label> <FormToggle id="carousel-indicators-form-toggle" label={ __( 'Show Indicators', 'elecwork' ) } checked={ carouselIndicators } onChange={ toggleIndicators } /> </PanelRow> <PanelRow> <label htmlFor="carousel-controls-form-toggle" > { __( 'Show Controls', 'elecwork' ) } </label> <FormToggle id="carousel-controls-form-toggle" label={ __( 'Show Controls', 'elecwork' ) } checked={ carouselControls } onChange={ toggleControls } /> </PanelRow> <PanelRow> <TextControl label={__("Slide Interval", "elecwork")} help={__("Text control help text", "elecwork")} value={ carouselInterval } onChange={ carouselInterval => setAttributes({ carouselInterval }) } /> </PanelRow> </PanelBody> </InspectorControls>, <div className={ className }> { ! imgID ? ( <MediaUploadCheck> <MediaUpload onSelect={ onSelectImage } type="image" value={ props.attributes.imgID } //allowedTypes={ 'image' } render={ ( { open } ) => ( <Button isPrimary onClick={ open }> Open Media Library </Button> ) } /> </MediaUploadCheck> ) : ( <Fragment> <p class="image-wrapper"> <img src={ imgURL } alt={ imgAlt } /> </p> </Fragment>, carouselControls && ( <Fragment> <a className="carousel-control-prev" href="#carouselExampleControls" role="button" data-slide="prev"> <span className="carousel-control-prev-icon" aria-hidden="true"></span> <span className="sr-only">Previous</span> </a> <a className="carousel-control-next" href="#carouselExampleControls" role="button" data-slide="next"> <span className="carousel-control-next-icon" aria-hidden="true"></span> <span className="sr-only">Next</span> </a> </Fragment> ) //end carousel controls check ) //end if has image } </div> ]; }, save: props => { const { attributes: { carouselIndicators, carouselControls, carouselInterval, imgURL, imgAlt }, attributes, className,} = props; return ( <div className={ className }> { <p> <img src={ imgURL } alt={imgAlt } /> </p>, carouselControls == true && ( <Fragment> <a className="carousel-control-prev" href="#carouselExampleControls" role="button" data-slide="prev"> <span className="carousel-control-prev-icon" aria-hidden="true"></span> <span className="sr-only">Previous</span> </a> <a className="carousel-control-next" href="#carouselExampleControls" role="button" data-slide="next"> <span className="carousel-control-next-icon" aria-hidden="true"></span> <span className="sr-only">Next</span> </a> </Fragment> ) } </div> ); }, }, );
April 4, 2020 at 9:52 am #139252Zac GordonKeymasterWhat is it that is not working. You’re on the right track of simplifying it till it works then adding the complexities back in, finding where it breaks. But what is the specific error or problem you’re having?
April 4, 2020 at 10:10 am #139254chrisdavies71ParticipantHi Zac,
If I take it back to basically what you have in the course examples it works – as in the image appears in the block as expected.
I can also add the HTML for the controls and when the image appears in the block so do the controls (expected behaviour)
When I try and add the conditional around the controls HTML the image no longer appears in the block. It seems this bit is what is tripping me up:
) : ( <Fragment> <p class="image-wrapper"> <img src={ imgURL } alt={ imgAlt } /> </p> </Fragment>, carouselControls && ( <-- THIS IS WHERE IT GOES WRONG <Fragment> <a className="carousel-control-prev" href="#carouselExampleControls" role="button" data-slide="prev"> <span className="carousel-control-prev-icon" aria-hidden="true"></span> <span className="sr-only">Previous</span> </a> <a className="carousel-control-next" href="#carouselExampleControls" role="button" data-slide="next"> <span className="carousel-control-next-icon" aria-hidden="true"></span> <span className="sr-only">Next</span> </a> </Fragment> ) //end carousel controls check ) //end if has image
- This reply was modified 4 years, 6 months ago by chrisdavies71. Reason: Code tidy up
April 4, 2020 at 10:27 am #139256Zac GordonKeymasterIs there an error you’re getting or does it just not render. It looks like you’re returning sybling elements. Try nesting both those in a single element perhaps? Also, you’re going from JSX back to JS so curly braces may be necessary as well.
Just for background context. What is your familiarity with JSX conditionals?
April 4, 2020 at 12:28 pm #139259chrisdavies71ParticipantHi Zac,
I was not getting any error it was just not rendering the image.
Just starting out really with Gutenberg/JSX but I found this link 7-ways-to-implement-conditional-rendering-in-react-applications and used the Ternary Operators solution.
Code now looks like this and works
) : ( <Fragment> <p class="image-wrapper"> <img src={ imgURL } alt={ imgAlt } /> </p> { carouselControls ? <Fragment> <a className="carousel-control-prev" href="#carouselExampleControls" role="button" data-slide="prev"> <span className="carousel-control-prev-icon" aria-hidden="true"></span> <span className="sr-only">Previous</span> </a> <a className="carousel-control-next" href="#carouselExampleControls" role="button" data-slide="next"> <span className="carousel-control-next-icon" aria-hidden="true"></span> <span className="sr-only">Next</span> </a> </Fragment> : '' } </Fragment> ) //end if has image
It could probably be tidied up in places. Thanks for the help though.
Chris
-
AuthorPosts
- You must be logged in to reply to this topic.