• Resolved Andrew Johnson

    (@solidrockmedia)


    How can I sort selections alphabetically in an autocomplete field within the admin dashboard?

    To give some more context on what I’m looking to do, I have a Pod which includes health insurances that I’d like to be alphabetized by name when they are displayed so the user can easily tell what has been already added:

    I understand that I can control how the actual selection list with the Customized ORDER BY relationship option but I’d like to order the options that have already been selected. I also know that I can control how the order in which items are displayed in a PHP template using something like an asort() function but neither of these have the desired effect in the admin dashboard.

    I’m thinking the simplest way to accomplish what I’m looking for would be to sort the list upon saving but I’m not sure where to begin with that.

    Any ideas on how to accomplish this?

Viewing 3 replies - 1 through 3 (of 3 total)
  • Plugin Support Paul Clark

    (@pdclark)

    The following PHP will add JavaScript to post.php and post-new.php screens to sort entries in the field insurances alphabetically in human-readable numeric order on load and any time the values are changed:

    <?php
    
    /**
     * @see https://docs.pods.io/code/dfv-js-api/
     * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Collator/Collator
     * @see https://fek.io/blog/how-to-observe-changes-to-the-dom-without-using-a-java-script-framework/
     */
    add_action(
    	'admin_print_footer_scripts',
    	function(){
    		global $pagenow;
    		if ( 'post.php' !== $pagenow && 'post-new.php' !== $pagenow ) {
    			return;
    		}
    ?>
    <script>
    document.addEventListener('DOMContentLoaded', function() {
    	if ('undefined' === typeof window.PodsDFV) {
    		return;
    	}
    
    	// Observe changes in the field values.
    	const observer = new MutationObserver(function(mutationList, observer) {
    		mutationList.forEach(mutation => {
    			if (mutation.type === 'childList') {
    				// If an input element is added or removed, sort.
    				for (const node of [...mutation.addedNodes, ...mutation.removedNodes]) {
    					if (node.nodeName === 'INPUT' && node.name.startsWith('pods_meta_insurances')) {
    						update_insurances_order();
    						return;
    					}
    				}
    			} else if (mutation.type === 'attributes' && mutation.attributeName === 'value') {
    				// If an input element has its value modified, sort.
    				if (mutation.target.nodeName === 'INPUT' && mutation.target.name.startsWith('pods_meta_insurances')) {
    					update_insurances_order();
    					return;
    				}
    			}
    		});
    	});
    
    	function start_observing() {
    		// .pods-form-ui-row-name-insurances corresponds to relationship field with ID "insurances".
    		const parentElement = document.querySelector('.pods-form-ui-row-name-insurances .pods-field-wrapper');
    
    		observer.observe(parentElement, {
    			attributes: true,
    			childList: true,
    			subtree: true
    		});
    	}
    
    	function update_insurances_order() {
    		const allFieldValuesAndConfigsOnScreen = window.PodsDFV.getFieldValues();
    		allFieldValuesAndConfigsOnScreen.forEach(function(fieldSet) {
    			if (
    				// pods_meta_insurances corresponds to relationship field with ID "insurances".
    				'undefined' === typeof fieldSet.fieldValues.pods_meta_insurances ||
    				0 === fieldSet.fieldValues.pods_meta_insurances.length
    			) {
    				return;
    			}
    
    			observer.disconnect();
    
    			// .pods-form-ui-row-name-insurances corresponds to relationship field with ID "insurances".
    			const insurance_options = document.querySelectorAll('.pods-form-ui-row-name-insurances .pods-dfv-pick-full-select__value-container > span');
    			let insurance_titles = [];
    
    			fieldSet.fieldValues.pods_meta_insurances.forEach(function(id, index) {
    				insurance_titles.push({
    					'id': id,
    					'title': insurance_options[index].textContent.trim()
    				});
    			});
    
    			const collator = new Intl.Collator('en-US', {
    				numeric: true
    			});
    			insurance_titles.sort(function(a, b) {
    				return collator.compare(a.title, b.title);
    			});
    
    			let sorted_insurance_ids = [];
    			insurance_titles.forEach(function(obj) {
    				sorted_insurance_ids.push(obj.id);
    			});
    
    			// pods_meta_insurances corresponds to relationship field with ID "insurances".
    			window.PodsDFV.setFieldValue(fieldSet.pod, fieldSet.itemId, 'pods_meta_insurances', sorted_insurance_ids);
    
    			start_observing();
    		});
    	}
    
    	update_insurances_order();
    	start_observing()
    });
    </script>
    <?php
    	},
    	1000
    );
    Thread Starter Andrew Johnson

    (@solidrockmedia)

    @pdclark, I did some testing and this appears to do exactly what I need. Thank you so much! You are a wizard!

    Plugin Contributor Scott Kingsley Clark

    (@sc0ttkclark)

    Pods 3.0 tweaks things a bit here, because of the way that code was referencing the field as “pods_meta_*” on the field values, that no longer is the case in Pods 3.0+ because it always references the real field name there.

    I updated the code to also use getFieldValue and setFieldValue to make it more concise there instead of fetching all field values.

    <?php
    
    /**
     * @see https://docs.pods.io/code/dfv-js-api/
     * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Collator/Collator
     * @see https://fek.io/blog/how-to-observe-changes-to-the-dom-without-using-a-java-script-framework/
     */
    add_action(
    	'admin_print_footer_scripts',
    	function () {
    		global $pagenow;
    		if ( 'post.php' !== $pagenow && 'post-new.php' !== $pagenow ) {
    			return;
    		}
    		?>
            <script>
                document.addEventListener('DOMContentLoaded', function () {
                    if ('undefined' === typeof window.PodsDFV) {
                        return;
                    }
    
                    // Observe changes in the field values.
                    const observer = new MutationObserver(function (mutationList, observer) {
                        mutationList.forEach(mutation => {
                            if (mutation.type === 'childList') {
                                // If an input element is added or removed, sort.
                                for (const node of [...mutation.addedNodes, ...mutation.removedNodes]) {
                                    if (node.nodeName === 'INPUT' && node.name.startsWith('pods_meta_insurances')) {
                                        update_insurances_order();
                                        return;
                                    }
                                }
                            } else if (mutation.type === 'attributes' && mutation.attributeName === 'value') {
                                // If an input element has its value modified, sort.
                                if (mutation.target.nodeName === 'INPUT' && mutation.target.name.startsWith('pods_meta_insurances')) {
                                    update_insurances_order();
                                    return;
                                }
                            }
                        });
                    });
    
                    function start_observing() {
                        // .pods-form-ui-row-name-insurances corresponds to relationship field with ID "insurances".
                        const parentElement = document.querySelector('.pods-form-ui-row-name-insurances .pods-field-wrapper');
    
                        observer.observe(parentElement, {
                            attributes: true,
                            childList: true,
                            subtree: true
                        });
                    }
    
                    function update_insurances_order() {
                        const insurances = window.PodsDFV.getFieldValue(null, null, 'insurances');
    
                        if (!insurances || 0 === insurances.length) {
                            return;
                        }
    
                        observer.disconnect();
    
                        // .pods-form-ui-row-name-insurances corresponds to relationship field with ID "insurances".
                        const insurance_options = document.querySelectorAll('.pods-form-ui-row-name-insurances .pods-dfv-pick-full-select__value-container > span');
                        let insurance_titles = [];
    
                        insurances.forEach(function (id, index) {
                            insurance_titles.push({
                                'id': id,
                                'title': insurance_options[index].textContent.trim()
                            });
                        });
    
                        const collator = new Intl.Collator('en-US', {
                            numeric: true
                        });
    
                        insurance_titles.sort(function (a, b) {
                            return collator.compare(a.title, b.title);
                        });
    
                        let sorted_insurance_ids = [];
                        insurance_titles.forEach(function (obj) {
                            sorted_insurance_ids.push(obj.id);
                        });
    
                        // Set the value.
                        window.PodsDFV.setFieldValue(null, null, 'insurances', sorted_insurance_ids);
    
                        start_observing();
                    }
    
                    update_insurances_order();
                    start_observing()
                });
            </script>
    		<?php
    	},
    	1000
    );
Viewing 3 replies - 1 through 3 (of 3 total)
  • The topic ‘Sorting Autocomplete Selections’ is closed to new replies.