Support

Account

Home Forums ACF PRO Dynamically populate select field AND data attributes?

Solving

Dynamically populate select field AND data attributes?

  • Hello, I have managed to dynamically populate a select field from custom values on an options page using the instructions for the acf/load_field/ filter. I would like to extend this to populating an adjacent number box when options are selected in the select field.

    I have actually crudely managed to do this like so:

    in functions.php

    function acf_load_product_type_options($field) {
    	$field['choices'] = array();
    	if (have_rows('type_of_product', 'option')) :
    		while (have_rows('type_of_product', 'option')) : the_row();
    			$value = get_sub_field('price');
    			$label = get_sub_field('product_type');
    			$field['choices'][$label . '#SEP#' . $value] = $label;
    		endwhile;
    	endif;
    	return $field;
    }
    add_filter('acf/load_field/name=product_picker', 'acf_load_product_type_options');

    This populates the product picker select field with the visible ‘product_type’ label and a constructed value consisting of the ‘product_type’ name, a ‘#SEP#’ seperator followed by the cost of the product ‘price’.

    A typical option HTML is <option value=”Product name#SEP#20″>Product name</option>

    I’ve written some jQuery which grabs the price, using the number after the #SEP# seperator which populates an adjacent empty number field whenever the select dropdown is changed. This new cost field seems to retain this value after a save and it’s changed whenever the select field is. So far so good. It works! Not only am I dynamically populating the select field I’m also using it to populate another.

    My issue will be when the value of a product is changed in my options page. If the product is raised to £25 then the option value will be ‘Product name#SEP#25’. This would mean the originally selected value will not be matched and the user will have to choose this again.

    One solution would be if I could somehow add a data attribute to the option tag like so: <option value=”Product name” data-cost=”20″>Product name</option>. This way I would keep the Product name value in place and I can pick up the cost with some slightly differeny jQuery.

    So is there any way you can think of that will allow me to dynamically populate this select dropdown without abusing the value field?

    Can the acf/load_field function be used to do this?

    Is it easy to customise and override an element of the acf/load_field function to add a data attribute?

    Is there a function I can run AFTER the new options values are set but before the ‘selected’ attribute has been set?

    I’d love to hear what you think as you might just solve my problem.

    Thanks in advance!

  • Ok, I’ve solved this crudely by putting the #SEP# separater and cost number in the label not the value field of the <option> tag. This way the label will remain unique unless changed and a change to the price will not effect which option has been preselected.

    Here’s the amended code:

    function acf_load_product_type_options($field) {
    	$field['choices'] = array();
    	if (have_rows('type_of_product', 'option')) :
    		while (have_rows('type_of_product', 'option')) : the_row();
    			$value = get_sub_field('price');
    			$label = get_sub_field('product_type');
    			$field['choices'][$label] = $label . '#SEP#' . $value;
    		endwhile;
    	endif;
    	return $field;
    }
    add_filter('acf/load_field/name=product_picker', 'acf_load_product_type_options');

    Then I use jQuery once the field has loaded to run through all select option fields on a page. If they have the #SEP# seperator in the label then I take the cost value and create a data attribute on the <option> tag:

    // ACF Select Dropdowns set up. Convert select option labels to data attributes
    	
    	$('.acf-field-select select option').each(function() {
    		var optionLabel = $(this).text();
    		// If select field has a label containing '#SEP#' string then process
    		if (optionLabel.indexOf('#SEP#') >= 0) {
    			var labelArray = optionLabel.split('#SEP#');
    			// Set 'cost-value' data attribute on <option> tag
    			var costValue = parseFloat(labelArray[1]).toFixed(2);
    			$(this).data('cost-value', costValue);
    			// Rewrite option label to remove '#SEP#' and cost figure
    			var optionDescriptionText = labelArray[0];
    			$(this).text(optionDescriptionText);
    		}
    	});

    That’s the set up. There is probably a better way to do this with PHP before the select field has been drawn. This way does show a flash of the ‘#SEP#’ and cost value in the actual select dropdown on the screen. It also seems to run twice for each field.

    Finally when a user changes the select dropdown we take the ‘cost’ value from that option’s new data attribute and use it to populate the next box:

    // ACF Form Fields Dynamically populated cost elements
    	
    	$('body').on('change', '.acf-field-select select', function() {
    		// If manually changed select dropdown has a 'cost-value' data attribute
    		if (typeof $(this).find('option:selected').data('cost-value') !== 'undefined') {
    			// Populate next box with cost value
    			var costValue = $(this).find('option:selected').data('cost-value');
    			$(this).closest('.acf-field-select').next().find('.acf-input input[type=number]').val(costValue);
    		}
    	});

    If somebody does know a safer way of doing this, maybe being able to add the data attributes to each option before the page is ‘ready’, then that would be great?

    Or suggest something else that should be triggering the data attribute creation apart from document ready to avoid what looks like duplication?

    Thanks!

  • Hi kingofmycastle,

    Actually i am very interested in finding a solution for this and i thought i was the only one trying to do this,

    i will share with you what i have found kind of useful but not a solution yet.

    1- there is a way to add a data-attribute to the wrapper of the field using
    $field['wrapper']['data-yourDataName'] = 'yourDataValue'; But unfortunately i cant find a way to add data attributes to the choices of select field “other than your way”,

    2- To solve the problem of user changing the values in option page, i would first populate the values normally from the option page like you stated in your post, then i would grab the value which is in the current post and check if it exist in the field[‘choices’], if its not exist means the original have been changed and i will add it to the array let me show you

    //This function will load a list of currencies from option page to the post page
    function tours_load_currency( $field ) 
        {
            $field['choices'] = array();
    
            //get the field
            $choices = get_field('available_currency', 'option', false);
    
            //seprate values by new line
            $choices = explode("\n", $choices);
    
            //array map the values
            $choices = array_map('trim', $choices);
    
            //fill the choices array with currency code and value :( .. which is really bad but no other way
            if( is_array($choices) ) 
            {        
                foreach( $choices as $choice ) 
                {
                    list($value, $text) = explode(" : ", $choice);            
                    $field['choices'][ $value . ' : ' .  $text] = $text;            
                }        
            }
    
            // get the current post select value from the database 
            $post_currency = get_post_meta(get_the_ID(),"tour_currency",true);
    
            // if we couldnt find the database value in the field["choices"], means that it was changed in options page
            if(!array_key_exists($post_currency, $field['choices']))
            {
                $post_currency_exploded = explode(' : ', $post_currency); // the drop down label
    
                //add the database value to the field["choices"] array one more time
                $field['choices'][$post_currency] = $post_currency_exploded[1];
            }
                    
            // return the field
            return $field;
        }
        add_filter('acf/load_field/name=tour_currency', 'tours_load_currency');

    again if any one knows a good way to add data-attributes for choices in a select field from server side will be really great

Viewing 3 posts - 1 through 3 (of 3 total)

You must be logged in to reply to this topic.