carbon-fields icon indicating copy to clipboard operation
carbon-fields copied to clipboard

Question: Is there a JavaScript method to repopulate select options?

Open oobi opened this issue 2 years ago • 5 comments

I'm trying to work out if this is even possible: Essentially I'm trying to build a select control with dynamically defined options based on another field value.

->set_options(function(){ $foo = // value of my other meta field return [ // options based on $foo ] });

I assume this would need to be a JavaScript thing in order to pick up changes and re-populate the select. I can see the API has methods to detect field changes and getFieldValue/setFieldValue.

Is there a way to repopulate the select options?

oobi avatar Nov 24 '22 01:11 oobi

Hello, did you happen to ever figure this out? I was trying to do something similar but couldn't quite get it figured out. I was trying to change a text field based on which select option was selected but got lost along the way.

Ryvix avatar Jun 20 '23 16:06 Ryvix

As far as I was able to determine it wasn’t possible… or at least not practical in my case. Where I ended up was a bit hacktastic so the attempt was abandoned.

oobi avatar Jun 21 '23 00:06 oobi

Thank you for the response!

I finally figured out a way to do it without trying to use React or Carbon Fields stuff since the docs seem to require some updating:

// Points to a function to enqueue the JS file only in the block editor
add_action( 'enqueue_block_editor_assets', 'my_block_editor_scripts' );
jQuery(function ($) {

    function update_fields() {
        const $textfield1 = $('input[name="myfield_text1"]');
        const $textfield2 = $('input[name="myfield_text2"]');
        const $select = $('select[name="myfield_select"]');

        jQuery.ajax({
            url: ajaxurl,
            data: {
                action: "admin_ajax",
                data: $select.val(),
                ajax_nonce: ajax_nonce
            },
            type: "POST",
            dataType: "json",
            success: function (response) {
                if (response.success) {
                    $textfield2.val(response.data.value);
                }
            }
        });
    }

    // When the select box is changed, update the fields.
    $(document).on('change', 'select[name="myfield_select"]', function () {
        update_fields();
    });

    // When the an input field is changed, wait a second, then update the fields.
    let timer = null;
    $(document).on('change', 'input[name="myfield_text1"]', function () {
        clearTimeout(timer);
        timer = setTimeout(function () {
            update_fields();
        }, 1000)
    });
});

And basically using wp_send_json_success with an array of the data for those fields to be updated with from the PHP side:

check_ajax_referer( 'ajax_nonce', 'ajax_nonce' );

if ( isset( $_POST['data'] ) ) {
    $value = 'something';
    wp_send_json_success( [
        'value' => $value,
    ] );
}

Something like that anyway. You would just have to adjust it a bit to update the select field instead. It doesn't really seem too hacky to me other than it's just using jQuery rather than React which seems perfectly ok to me since I don't think I'm a fan of it anyway.

Ryvix avatar Jun 21 '23 14:06 Ryvix

In my previous code inside the ajax response replace this:

$textfield2.val(response.data.value);

With this:

const field_key = 'field-name';
block.attributes.data[field_key ] = response.data.value;
wp.data.dispatch('core/block-editor').updateBlock(block.clientId, {attributes: block.attributes});

And add this before the ajax request to get the block:

const block = wp.data.select('core/block-editor').getSelectedBlock();

Ryvix avatar Oct 19 '23 23:10 Ryvix

I just wanted to follow up and post another solution that doesn't necessarily use blocks in case anyone was trying to do it that way too. For example when using a theme options page. Something like this will update the value of a field. In my case I submit an AJAX request and store the values directly that way as well since I'm doing some other things with them but I didn't include that in the example.

jQuery(document).ready(function ($) {
    const {select, dispatch} = window.cf.vendor['@wordpress/data'];
    const metaboxes = select('carbon-fields/metaboxes');
    const {updateFieldValue} = dispatch('carbon-fields/metaboxes');
    
    const fields = metaboxes.getFields();
    let field = Object.values(fields).find(f => f.base_name === 'your-option-name');
    
    updateFieldValue(field.id, 'your new value');
});

Ryvix avatar Nov 05 '23 01:11 Ryvix