Existe alguma maneira de preencher novamente as opções de um Html Select sem disparar o evento Change (usando jQuery)?

StackOverflow https://stackoverflow.com/questions/44903

Pergunta

Eu tenho várias seleções:

<select id="one">
  <option value="1">one</option>
  <option value="2">two</option>
  <option value="3">three</option>
</select>
<select id="two">
  <option value="1">one</option>
  <option value="2">two</option>
  <option value="3">three</option>
</select>

O que eu quero é selecionar "um" da primeira seleção e depois remover essa opção da segunda.Então, se você selecionar "dois" do segundo, quero que esse seja removido do primeiro.

Aqui está o JS que tenho atualmente:

$(function () {
    var $one = $("#one");
    var $two = $("#two");

    var selectOptions = [];
    $("select").each(function (index) {
        selectOptions[index] = [];
        for (var i = 0; i < this.options.length; i++) {
            selectOptions[index][i] = this.options[i];
        }
    });

    $one.change(function () {
        var selectedValue = $("option:selected", this).val();
        for (var i = 0; i < selectOptions[1].length; i++) {
            var exists = false;
            for (var x = 0; x < $two[0].options.length; x++) {
                if ($two[0].options[x].value == selectOptions[1][i].value)
                    exists = true;
            }
            if (!exists)
                $two.append(selectOptions[1][i]);
        }

        $("option[value='" + selectedValue + "']", $two).remove();
    });
    $two.change(function () {
        var selectedValue = $("option:selected", this).val();
        for (var i = 0; i < selectOptions[0].length; i++) {
            var exists = false;
            for (var x = 0; x < $one[0].options.length; x++) {
                if ($one[0].options[x].value == selectOptions[0][i].value)
                    exists = true;
            }
            if (!exists)
                $one.append(selectOptions[0][i]);
        }

        $("option[value='" + selectedValue + "']", $one).remove();
    });
});

Mas quando os elementos são repovoados, ele dispara o evento change no select cujas opções estão mudando.Eu tentei apenas definir o disabled atributo na opção que desejo remover, mas isso não funciona com o IE6.

Foi útil?

Solução

Não sou (atualmente) um usuário de jQuery, mas posso dizer que você precisa desconectar temporariamente seu manipulador de eventos enquanto preenche novamente os itens ou, pelo menos, definir um sinalizador que você testa e com base em seu valor, lidar com a mudança.

Outras dicas

Aqui está o código final que acabei usando, o sinalizador (changeOnce) funcionou muito bem, obrigado @Jason.

$(function () {
    var $one = $("#one");
    var $two = $("#two");

    var selectOptions = [];
    $("select").each(function (index) {
        selectOptions[index] = [];
        for (var i = 0; i < this.options.length; i++) {
            selectOptions[index][i] = this.options[i];
        }
    });

    var changeOnce = false;
    $one.change(function () {
        if (changeOnce) return;
        changeOnce = true;
        var selectedValue = $("option:selected", this).val();
        filterSelect(selectedValue, $two, 1);
        changeOnce = false;
    });
    $two.change(function () {
        if (changeOnce) return;
        changeOnce = true;
        var selectedValue = $("option:selected", this).val();
        filterSelect(selectedValue, $one, 0);
        changeOnce = false;
    });

    function filterSelect(selectedValue, $selectToFilter, selectIndex) {
        for (var i = 0; i < selectOptions[selectIndex].length; i++) {
            var exists = false;
            for (var x = 0; x < $selectToFilter[0].options.length; x++) {
                if ($selectToFilter[0].options[x].value == selectOptions[selectIndex][i].value)
                    exists = true;
            }
            if (!exists)
                $selectToFilter.append(selectOptions[selectIndex][i]);
        }
        $("option[value='" + selectedValue + "']", $selectToFilter).remove();
        sortSelect($selectToFilter[0]);
    }

    function sortSelect(selectToSort) {
        var arrOptions = [];

        for (var i = 0; i < selectToSort.options.length; i++)  {
            arrOptions[i] = [];
            arrOptions[i][0] = selectToSort.options[i].value;
            arrOptions[i][1] = selectToSort.options[i].text;
            arrOptions[i][2] = selectToSort.options[i].selected;
        }

        arrOptions.sort();

        for (var i = 0; i < selectToSort.options.length; i++)  {
            selectToSort.options[i].value = arrOptions[i][0];
            selectToSort.options[i].text = arrOptions[i][1];
            selectToSort.options[i].selected = arrOptions[i][2];
        }
    }
});

Ou você pode simplesmente ocultar a opção que não deseja mostrar...

function hideSelected($one, $two)
{
    $one.bind('change', function()
    {
        var val = $one.val();
        $two.find('option:not(:visible)').show().end()
            .find('option[value='+val+']').hide().end();
    })
}
hideSelected($one, $two);
hideSelected($two, $one);

EDITAR:Desculpe, este código não funciona com o IE6 ...

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top