3

I am getting this error when I add a value to the buttonUrl input.

A component is changing an uncontrolled input of type url to be controlled. Input elements should not switch from uncontrolled to controlled (or vice versa). Decide between using a controlled or uncontrolled input element for the lifetime of the component.

this is the code for my block.

Also what do i need to change to get a span inside of my h3 subhead.

I have been going around for ages with this. Cheers

 ( function ( blocks, editor, i18n, element, components, _ ) {
    const __ = i18n.__;
    const el = element.createElement;
    const RichText = editor.RichText;
    const MediaUpload = editor.MediaUpload;
    const InspectorControls = editor.InspectorControls;
    const PanelBody = components.PanelBody;
    const TextControl = components.TextControl;
    const SelectControl = components.SelectControl;

    blocks.registerBlockType('unify/about-block', {
        title: __('Unify About Block', 'unify'),
        icon: 'align-left',
        category: 'layout',
        attributes: {
            title: {
                type: 'array',
                source: 'children',
                selector: 'h2',
            },
            subhead: {
                type: 'array',
                source: 'children',
                selector: 'h3',
            },
            content: {
                type: 'string'
            },
            mediaID: {
                type: 'number',
                default: 0
            },
            mediaURL: {
                type: 'string',
                source: 'attribute',
                selector: 'img',
                attribute: 'src',
            },
            buttonText: {
                type: 'string',
                default: ''
            },
            buttonUrl: {
                type: 'url',
                default: ''
            },
            blockColor: {
                type: 'string',
                default: 'brand-dark-blue'
            },
        },
        edit: function ( props ) {
            const attributes = props.attributes;
            const onSelectImage = function ( media ) {
                return props.setAttributes({
                    mediaURL: media.url,
                    mediaID: media.id,
                });
            };
            return el(
                'div',
                {
                    className: props.className
                },
                el(
                    'div',
                    { className: 'column block-content' },
                    el(
                        RichText,
                        {
                            tagName: 'h2',
                            inline: true,
                            placeholder: __('Title', 'unify'),
                            value: attributes.title,
                            onChange: function ( value ) {
                                props.setAttributes({ title : value });
                            },
                        }
                    ),
                    el(
                        RichText,
                        {
                            tagName: 'h3',
                            inline: true,
                            placeholder: __('Subhead', 'unify'),
                            value: attributes.subhead,
                            onChange: function ( value ) {
                                props.setAttributes({ subhead : value });
                            },
                        }
                    ),
                    el(
                        RichText,
                        {
                            tagName: 'p',
                            placeholder: i18n.__('Content', 'unify'),
                            value: attributes.content,
                            onChange: function ( value ) {
                                props.setAttributes({ content : value });
                            }
                        }
                    ),
                    el(
                        'a',
                        {
                            className: 'components-button button button-large is-primary',
                            href: attributes.buttonURL
                        },
                        attributes.buttonText
                    )
                ),
                el(
                    'div',
                    {
                        className: 'column block-image'
                    },
                    el(
                        MediaUpload,
                        {
                            onSelect: onSelectImage, allowedTypes: 'image', value: attributes.mediaID,
                            render: function ( obj ) {
                                return el(
                                    components.Button,
                                    {
                                        className: attributes.mediaID ? 'image-button' : 'button button-large', onClick: obj.open
                                    },
                                    ! attributes.mediaID ? __('Upload Image', 'unify') : el('img', { src: attributes.mediaURL })
                                );
                            },
                        }
                    )
                ),
                el(
                    InspectorControls,
                    {
                        key: 'inspector'
                    },
                    el(
                        PanelBody,
                        { title: i18n.__('Button Link'), className: 'block-button-link', initialOpen: true },
                        el(
                            TextControl,
                            {
                                type: 'url',
                                label: i18n.__('Enter the destination URL for the button'),
                                value: props.attributes.buttonURL,
                                onChange: function ( newButtonURL ) {
                                    console.log(newButtonURL);
                                    props.setAttributes({ buttonURL: newButtonURL });
                                }
                            }
                        ),
                        el(
                            TextControl,
                            {
                                type: 'text',
                                label: i18n.__('Button Text', 'unify'),
                                value: attributes.buttonText,
                                onChange: function (newButtonText) {
                                    props.setAttributes({ buttonText: newButtonText })
                                }
                            }
                        )
                    ),
                    el(
                        PanelBody,
                        { title: i18n.__('Color Settings'), className: 'block-color', initialOpen: false },
                        el(
                            SelectControl,
                            {
                                type: 'string',
                                label: i18n.__('Choose the highlight color for the block'),
                                value: attributes.blockColor ? attributes.blockColor : '',
                                options: [{
                                    label: 'Dark Blue',
                                    value: 'brand-dark-blue'
                                },{
                                    label: 'Light Blue',
                                    value: 'brand-blue'
                                },{
                                    label: 'Green',
                                    value: 'brand-green'
                                },{
                                    label: 'Purple',
                                    value: 'brand-purple'
                                }],
                                onChange: function ( value ) {
                                    props.setAttributes({ blockColor : value });
                                },
                            }
                        ),
                    ),
                )
            )
        },
        save: function ( props ) {
            const attributes = props.attributes;
            return el(
                'section',
                {
                    className: 'about-block-section ' + attributes.blockColor
                },
                el(
                    'div',
                    {
                        className: 'grid-container'
                    },
                    el(
                        'div',
                        {
                            className: 'grid-x grid-padding-x align-center-middle'
                        },
                        el(
                            'div',
                            {
                                className: 'cell small-12 medium-6 large-6 small-order-2 medium-order-1 about-block-image-outer'
                            },
                            el(
                                'div',
                                {
                                    className: 'about-block-image square-aspect-ratio'
                                },
                                attributes.mediaURL ? el(
                                    'img',
                                    {
                                        src: attributes.mediaURL
                                    }
                                ) : ''
                            ),
                        ),
                        el(
                            'div',
                            {
                                className: 'cell small-12 medium-6 large-5 large-offset-1 small-order-2 medium-order-1 about-block-content-outer'
                            },
                            attributes.title ? el(
                                RichText.Content,
                                {
                                    tagName: 'h2',
                                    className: 'about-block-content-title',
                                    value: attributes.title,
                                }
                            ) : '',
                            attributes.subhead ? el(
                                RichText.Content,
                                {
                                    tagName: 'h3',
                                    className: 'about-block-content-subhead',
                                    value: attributes.subhead,
                                }
                            ) : '',
                            attributes.content ? el(
                                RichText.Content,
                                {
                                    tagName: 'p',
                                    className: 'about-block-content-body',
                                    value: attributes.content
                                }
                            ) : '',
                            attributes.buttonURL && attributes.buttonText ? el(
                                'a',
                                {
                                    href: attributes.buttonURL,
                                    className: 'button about-block-content-button'
                                },
                                attributes.buttonText,
                                el(
                                    'i',
                                    { className: 'fas fa-arrow-right'}
                                )
                            ) : ''
                        )
                    )
                )
            )
        },
    });
} )(
    window.wp.blocks,
    window.wp.blockEditor,
    window.wp.i18n,
    window.wp.element,
    window.wp.components,
    window._
);

1 Answers1

2

This is likely long after you've resolved this but I believe it'll help someone else. That issue is usually down to a component's value being set as undefined initially. See A component is changing an uncontrolled input of type text to be controlled error in ReactJS

From your error message:

A component is changing an uncontrolled input of type url to be controlled. Input elements should not switch from uncontrolled to controlled (or vice versa). Decide between using a controlled or uncontrolled input element for the lifetime of the component.

You have one component of type URL - TextControl and the value being passed to it is value: props.attributes.buttonURL

So based on that, I believe buttonURL is undefined at some point, which results in that error. To address that, set a default value for buttonURL in the edit.

edit: function ( props ) {
            const attributes = props.attributes;
            const buttonURL = props.attributes && props.attributes.buttonURL ?? props.attributes.buttonURL : '' // Decide on an appropriate default
            const onSelectImage = function ( media ) {
                return props.setAttributes({
                    mediaURL: media.url,
                    mediaID: media.id,
                });
            };

Then use it in the TextControl component - value: props.attributes.buttonURL becomes value: buttonURL

kakoma
  • 1,179
  • 13
  • 17