How to disable options in select elements that are already selected in another select element

27.09.2018 by Jens Martsch

For a project of one of my customers I needed a possibility to assign different properties to an object (the "object" is a room in my case).

But... if a property was selected before, then the possibility to add this property again should be disabled.

As I found no reliable solution after some googling, I wrote a JavaScript (jQuery) to the rescue.

Here you can see it in action

Live Example

See the Pen Disable options in selects that have been selected in another select by Jens Martsch (@jmar) on CodePen.

Use it in ProcessWire

I integrated a slightly modified version of the script into ProcessWire where it should be used in conjunction with ProFields: Table and a page reference field (which is used for the property). Here is what I did:

create a admin.js file in site/templates/scripts

function disableUsedOptions($table) {
    $selects = $table.find("select");
    $selects.on("change", function () {
        $selects = $table.find("select");

        if (config.debug === true) console.log("In table:");
        if (config.debug === true) console.log($table);
        if (config.debug === true) console.log("there are " + $selects.length + " selects");
        if ($selects.length <= 1) return;
        let selected = [];

        $selects.each(function (index, select) {
            if (select.value !== "") {
                selected.push(select.value);
            }
        });

        if (config.debug === true) console.log("option values, that are being deactivated: " + selected);
        if (config.debug === true) console.log($(this));
        $table.find("option").prop("disabled", false);
        for (var index in selected) {
            $table
                .find('option[value="' + selected[index] + '"]:not(:selected)')
                .prop("disabled", true);
        }
    });
    $selects.trigger("change");
}



$(document).ready(function () {
    $tables = $("table.InputfieldTable:not(.InputfieldTableSearch)");
    $tables.each(function () {
        $table = $(this);
        disableUsedOptions($table);
    });
});

then add the following lines in site/templates/admin.php

$config->scripts->add($config->urls->templates . "scripts/admin.js");
$config->styles->add($config->urls->templates . "styles/admin.css");

before the line that reads

require($config->paths->adminTemplates . 'controller.php');

You could also use a module which adds a hook before ProcessPageEdit::buildForm to load the script.