Carbon-fields: JS broken with oEmbed field and conditional logic

Created on 29 Jan 2019  ยท  10Comments  ยท  Source: htmlburger/carbon-fields

Version

  • Carbon Fields: 3.0.2
  • WordPress: 4.9.8
  • PHP: 7.2

Expected Behavior

Should work. ๐Ÿ‘

Actual Behavior

Does not work. ๐Ÿ‘Ž
JS breaks, and prevents the user to make other JS-manages actions, like removing a field.

Container definition

Container::make('post_meta', 'Foo')
    ->where('post_type', '=', 'page')
    ->add_fields(array(
        Field::make('checkbox', 'bar', 'Bar'),
        Field::make('oembed', 'baz', 'Baz')
            ->set_conditional_logic(array(
                array(
                    'field' => 'bar',
                    'value' => true,
                )
            ))
    ));

Steps to Reproduce the Problem

  1. Create the container
  2. Edit a page in WP backoffice
  3. Open the console and see the 7, 8, 9โ€ฆ 345, 346โ€ฆ errors
  4. Bonus: with any complex field on the same page, you'll no longer able to remove a field

Comments

When adding an oembed field with conditional logic, Carbon Fields JavaScript breaks. You'll see a huge amount of errors in the console:

Uncaught TypeError: Cannot read property 'getBoundingClientRect' of null
    at eval (index.js:132)

The related code (in assets/js/fields/components/oembed/index.js:

export const enhance = compose(
    โ€ฆ

    /**
     * Attach the setup hooks.
     */
    withSetup({
        componentDidMount() {
            const {
                field,
                ui,
                setupField,
                handleSearchSubmit,
            } = this.props;

            setupField(field.id, field.type, ui);

            const domNode = ReactDOM.findDOMNode(this);

            const i = setInterval(() => {
                if (domNode.getBoundingClientRect().width > 0) {
                    clearInterval(i);
                    handleSearchSubmit(field.value);
                }
            }, 100);
        }
    }),
);
[type] bug

All 10 comments

Hi @zessx,

The code that you've posted is from Carbon Fields@2. Can you try with Carbon Fields@3 to see if the problem persist? Thanks.

Hi @vvasilev-

As stated in the issue, I'm using Carbon Fields 3.0.2.
I checked my code, but I don't see anything that is not in the CF@3 documentation.

What makes you think it's CB@2 ?

I'm getting a very similar problem, also Carbon Fields 3.0.2.

My code is as follows

<?php

use Carbon_Fields\Carbon_Fields;
use Carbon_Fields\Container;
use Carbon_Fields\Field;

add_action('after_setup_theme', function () {
    Carbon_Fields::boot();
});

add_action('admin_init', function () {
    remove_post_type_support('page', 'editor');
});


function pascal_to_snake($pascal)
{
    $snake = preg_replace('/[A-Z]/', '_$0', $pascal);
    $snake = strtolower($snake);
    $snake = ltrim($snake, '_');
    return $snake;
}

class VideoBlock
{
    const STYLE_VIDEO_FULL = 'video_full';
    const STYLE_VIDEO_COLUMN = 'video_column';
    public static function getFields()
    {
        $condition = [
            [
                'field' => 'video_block_style',
                'value' => VideoBlock::STYLE_VIDEO_COLUMN,
            ]
        ];
        return [
            Field::make('select', 'video_block_style', 'Style')
                ->add_options([
                    VideoBlock::STYLE_VIDEO_FULL => 'Full Width Video',
                    VideoBlock::STYLE_VIDEO_COLUMN => 'Two Columns with Text',
                ]),
            Field::make('text', 'video_block_title', 'Title'),
            Field::make('image', 'video_block_preview', 'Preview Image'),
            Field::make('oembed', 'video_block_embed', 'Video')
                ->set_required(true),
            Field::make('text', 'video_block_subheading', 'Subheading')
                ->set_conditional_logic($condition),
            Field::make('rich_text', 'video_block_description', 'Description')
                ->set_conditional_logic($condition),
            Field::make('text', 'video_block_link_text', 'Button text')
                ->set_conditional_logic($condition)
        ];
    }
}

class CTABlock
{
    const STYLE_IMAGE_FULL = 'image_full';
    const STYLE_IMAGE_COLUMN = 'image_column';
    public static function getFields()
    {
        return [
            Field::make('image', 'ctablock_image', 'Image'),
            Field::make('text', 'ctablock_title', 'Title'),
            Field::make('textarea', 'ctablock_description', 'Description'),
            Field::make('text', 'ctablock_link_text', 'Button text'),
            Field::make('select', 'ctablock_style', 'Style')
                ->add_options([
                    CTABlock::STYLE_IMAGE_FULL => 'Image as background',
                    CTABlock::STYLE_IMAGE_COLUMN => 'Image in right column',
                ]),
        ];
    }
}

class ContentBlocks
{
    protected static $defaultBlocks = [
        'CTABlock',
        'VideoBlock'
    ];
    const BLOCKS_FIELD_NAME = 'content_blocks';

    public static function getFields()
    {
        return static::getFieldsFromList(static::$defaultBlocks);
    }

    protected static function getFieldsFromList(array $selectedFields = [])
    {
        $field = Field::make('complex', static::BLOCKS_FIELD_NAME, 'Content Blocks')
            ->set_collapsed(true)
            ->setup_labels([
                'singular_name' => 'Block',
                'plural_name' => 'Blocks'
            ]);
        foreach ($selectedFields as $block) {
            $slug = pascal_to_snake($block);
            $class = $block;
            $field->add_fields($slug, $class::getFields());
        }
        return [$field];
    }
}

add_action('carbon_fields_register_fields', function () {
    Container::make('post_meta', 'Content Blocks')
        ->where('post_type', '=', 'page')
        ->add_fields(ContentBlocks::getFields());
}, 10);

Steps to reproduce the bug:

  1. Create multiple blocks including at least one Video block
  2. Attempt to delete ANY block
  3. All blocks disappear an JS errors out.
[Error] TypeError: undefined is not an object (evaluating 'fieldsHolder.fields')
    getFieldsFromFieldsHolder (index.js:41:195)
    output (index.js:129)
    (anonymous function) (index.js:66)
    (anonymous function) (index.es.js:219)
    (anonymous function) (readme.js:53)
    (anonymous function) (callbag-distinct-until-changed.es.js:34)
    (anonymous function) (readme.js:48)
    forEach
    globalListener (registry.js:58)
    (anonymous function) (namespace-store.js:72)
    dispatch (redux.js:229)
    (anonymous function) (resolvers-cache-middleware.js:50)
    proxyDispatch (index.js:79:121)
    proxyDispatch
    (anonymous function) (index.js:138)
    (anonymous function) (index.js:135)
    (anonymous function) (group.js:82)
    callCallback (react-dom.development.js:149)
    dispatchEvent
    invokeGuardedCallbackDev (react-dom.development.js:199)
    invokeGuardedCallback (react-dom.development.js:256)
    invokeGuardedCallbackAndCatchFirstError (react-dom.development.js:270)
    executeDispatch (react-dom.development.js:561)
    executeDispatchesInOrder (react-dom.development.js:583)
    executeDispatchesAndRelease (react-dom.development.js:680)
    forEachAccumulated (react-dom.development.js:662)
    runEventsInBatch (react-dom.development.js:816)
    runExtractedEventsInBatch (react-dom.development.js:824)
    handleTopLevel (react-dom.development.js:4820)
    batchedUpdates$1 (react-dom.development.js:18932)
    batchedUpdates (react-dom.development.js:2150)
    dispatchEvent (react-dom.development.js:4899)
    interactiveUpdates$1 (react-dom.development.js:18987)
    dispatchInteractiveEvent (react-dom.development.js:4876)
    dispatchInteractiveEvent

I've got another conditional oEmbed block that isn't causing the issue above with complex fields, but is throwing a ton on JS errors, and seems to be causing the browser tab to draw a lot of memory. Errors are as follows:

TypeError: null is not an object (evaluating '_this2.node.current.getBoundingClientRect')
Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.
    in FileField
    in Unknown (created by WithFilters(FileField))
    in WithFilters(FileField) (created by WithEffects)
    in WithEffects (created by ComponentWithDispatch)
    in ComponentWithDispatch (created by Context.Consumer)
    in WithDispatch(WithEffects) (created by ComponentWithDispatch)
    in ComponentWithDispatch (created by Context.Consumer)
    in WithDispatch(WithDispatch(WithEffects)) (created by WithEffects)
    in WithEffects (created by ComponentWithSelect)
    in ComponentWithSelect (created by Context.Consumer)
    in WithSelect(WithEffects) (created by ComponentWithDispatch)
    in ComponentWithDispatch (created by Context.Consumer)
    in WithConditionalLogic(WithDispatch(WithDispatch(WithEffects))) (created by ComponentWithDispatch)
    in ComponentWithDispatch (created by Context.Consumer)
    in WithDispatch(WithConditionalLogic(WithDispatch(WithDispatch(WithEffects)))) (created by ComponentWithSelect)
    in ComponentWithSelect (created by Context.Consumer)
    in WithField(WithConditionalLogic(WithDispatch(WithDispatch(WithEffects)))) (created by WithFilters(WithFilters(FileField)))
    in WithFilters(WithFilters(FileField)) (created by ComplexGroup)
    in div (created by Field)
    in div (created by Field)
    in Field
    in Unknown (created by WithFilters(Field))
    in WithFilters(Field) (created by ComponentWithSelect)
    in ComponentWithSelect (created by Context.Consumer)
    in WithSelect(WithFilters(Field)) (created by WithFilters(WithSelect(WithFilters(Field))))
    in WithFilters(WithSelect(WithFilters(Field))) (created by ComponentWithDispatch)
    in ComponentWithDispatch (created by Context.Consumer)
    in WithDispatch(WithFilters(WithSelect(WithFilters(Field)))) (created by ComponentWithSelect)
    in ComponentWithSelect (created by Context.Consumer)
    in WithField(WithFilters(WithSelect(WithFilters(Field)))) (created by ComplexGroup)
    in div (created by ComplexGroup)
    in div (created by ComplexGroup)
    in ComplexGroup (created by ComplexField)
    in div (created by ComplexField)
    in Sortable (created by ComplexField)
    in ComplexField (created by ComplexField)
    in ComplexField
    in Unknown (created by ComponentWithDispatch)
    in ComponentWithDispatch (created by Context.Consumer)
    in WithDispatch(Component) (created by ComponentWithSelect)
    in ComponentWithSelect (created by Context.Consumer)
    in WithSelect(WithDispatch(Component)) (created by WithFilters(ComplexField))
    in WithFilters(ComplexField) (created by WithEffects)
    in WithEffects (created by ComponentWithDispatch)
    in ComponentWithDispatch (created by Context.Consumer)
    in WithDispatch(WithEffects) (created by ComponentWithDispatch)
    in ComponentWithDispatch (created by Context.Consumer)
    in WithDispatch(WithDispatch(WithEffects)) (created by WithEffects)
    in WithEffects (created by ComponentWithSelect)
    in ComponentWithSelect (created by Context.Consumer)
    in WithSelect(WithEffects) (created by ComponentWithDispatch)
    in ComponentWithDispatch (created by Context.Consumer)
    in WithConditionalLogic(WithDispatch(WithDispatch(WithEffects))) (created by ComponentWithDispatch)
    in ComponentWithDispatch (created by Context.Consumer)
    in WithDispatch(WithConditionalLogic(WithDispatch(WithDispatch(WithEffects)))) (created by ComponentWithSelect)
    in ComponentWithSelect (created by Context.Consumer)
    in WithField(WithConditionalLogic(WithDispatch(WithDispatch(WithEffects)))) (created by WithFilters(WithFilters(ComplexField)))
    in WithFilters(WithFilters(ComplexField)) (created by Container)
    in div (created by Field)
warningWithoutStack โ€” react-dom.js:500
warnAboutUpdateOnUnmounted โ€” react-dom.js:17123
scheduleWork โ€” react-dom.js:18499
enqueueSetState โ€” react-dom.js:12437
setState โ€” react.js:460
(anonymous function) โ€” index.js:71
promiseReactionJob
8index.js:132

Any news on this guys?
cc @vvasilev-

Hi, I also encounter the same problem. Any clue how to address this?

All I could do was remove the conditional logic on the fields and add help text to the fields explaining the intended functionality. Seems like this issue is being neglected with the now quite inappropriate [status] needs more information flag.

up

The issue has been fixed in v3.1.6. Please update ๐Ÿ™‚

Was this page helpful?
0 / 5 - 0 ratings

Related issues

dmhendricks picture dmhendricks  ยท  3Comments

bjoernhasse picture bjoernhasse  ยท  3Comments

ittikorns picture ittikorns  ยท  3Comments

abdusfauzi picture abdusfauzi  ยท  3Comments

Mick00 picture Mick00  ยท  3Comments