jQuery选项appendTo select移动到下一个选项而不是选择一个

时间:2014-11-05 04:38:05

标签: javascript jquery html select

http://jsfiddle.net/j3oh6s3a/

由于某些原因,向SELECT标记添加选项不会选择selected ='selected'属性选项,而是选择列表中的下一个选项。

请参阅上面的jfiddle。

<select id="category">
    <option value='1'>Categroy 1</option>
    <option value='2'>Categroy 2</option>
    <option value='3'>Categroy 3</option>
</select>
<select id="sub-category">
    <option value='1' data-parentid='1'>Car1</option>
    <option value='2' data-parentid='1'>Car2</option>
    <option selected='selected' value='3' data-parentid='1'>Car3</option>
    <option value='4' data-parentid='1'>Car4</option>
    <option value='5' data-parentid='1'>Car5</option>
    <option value='6' data-parentid='2'>Car6</option>
    <option value='7' data-parentid='2'>Car7</option>
    <option value='8' data-parentid='2'>Car8</option>
    <option value='9' data-parentid='3'>Car9</option>
    <option value='10' data-parentid='3'>Car10</option>
    <option value='11' data-parentid='3'>Car11</option>
    <option value='12' data-parentid='3'>Car12</option>
</select>

$(document).ready(function(){
    var allsuboptions = $('#sub-category option').remove();
    var selectedOptions = allsuboptions.filter(function () {
        return $(this).data('parentid').toString() === $('#category').val().toString();
    });
    selectedOptions.appendTo('#sub-category');
});

在上面的示例中,应该选择Car3,但是在将选项附加到选择后选择Car4。

5 个答案:

答案 0 :(得分:3)

这是一个棘手(有趣)的问题。

如果您在不同浏览器上测试小提琴,您会看到所选值发生变化:Chrome(Car4),IE(Car3),Firefox(Car5)。所以我对你的小提琴做了一点改变,以“证明一个理论”。您可以在此链接上看到更改:http://jsfiddle.net/j3oh6s3a/1/。我只在过滤器循环中添加了一个日志,因此我可以在每次迭代中看到所选元素:

if ($(this).is(":selected")) { console.log("Selected value = " + $(this).val()) };

现在发生这种情况(或者至少是我的理论):从列表中删除所选元素后,每个浏览器都会继续,但认为足以确定所选选项。在这种情况下,每个浏览器将以不同的方式进行:

  • 由于所选选项已被删除, Chrome 会自动(默认情况下)选择列表中剩余的option(Car4)。将此选项发送到新列表时,会自动选择该选项,因为它比先前选择的选项更新。日志是:3,4。

  • Internet Explorer 不执行任何操作,并以相同的方式复制每个元素,而不关心它们是否被选中。原始选定值将是最终选定值(Car3)。日志是:3。

  • Firefox 将像Chrome一样继续,但每次从列表中删除所选元素时,将选择其余元素的第一个选项。日志是:3,4,5,6,7,8,9,10,11,12;但是当列表中插入的最后一个选项是5时,它将是所选的选项。

我稍后会查看是否可以找到任何信息来获取此信息,但它必须是明天,因为它有点晚了。

答案 1 :(得分:3)

jQuery .remove.append内部使用.removeChild.appendChild方法删除/插入子元素。

理论:removeChild / appendChild维护属性但不维护元素的属性(维持选择状态)

当您使用removeChild然后appendChild重新添加选项时,将保留属性,但不保留元素的属性。您可以在此处详细了解 .prop() vs .attr()

总之,属性是HTML中定义的初始值,它们被解析为由浏览器设置为Element的属性,但是设置属性并不能保证设置属性。

$(function() {
  var categoryDD = document.getElementById('category');
  var removedOptions = remove.call(categoryDD.options);
  add.call(categoryDD, removedOptions);
});

function add(options) { //add all options
  for (var i = 0; i < options.length; i++) {
    this.appendChild(options[i]);
  }
}

function remove() { //removes all options
  var el, returnOpt = [];
  while (this.length) {
    el = this[0];
    returnOpt.push(el.parentNode.removeChild(el));
  }
  return returnOpt;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<select id="category">
  <option value='1'>Categroy 1</option>
  <option value='2' selected="selected">Categroy 2</option>
  <option value='3'>Categroy 3</option>
  <option value='4'>Categroy 4</option>
  <option value='5'>Categroy 5</option>
  <option value='6'>Categroy 6</option>
</select>

测试结果:

在测试上面的代码片段时,IE 10和FF产生了相同的结果,即从下拉列表中选择最后一个选项,但是Chrome似乎有问题,因为它始终从原始选择中选择下一个选项。 IE 10和FF的结果对于“不维持状态”有点意义,但Chrome行为似乎是一个错误。

以上是基于我的测试用例的理论,但是我找不到一个说明相同的合法参考。

无论如何,请尝试以下解决方案以获得一致的输出。

解决方案1:仅删除不等于的选项到parentId。

$('#sub-category option').filter(function () {
    return $(this).data('parentid').toString() !== $('#category').val().toString();
}).remove();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<select id="category">
    <option value='1'>Categroy 1</option>
    <option value='2'>Categroy 2</option>
    <option value='3'>Categroy 3</option>
</select>
<select id="sub-category">
    <option value='1' data-parentid='1'>Car1</option>
    <option value='2' data-parentid='1'>Car2</option>
    <option selected='selected' value='3' data-parentid='1'>Car3</option>
    <option value='4' data-parentid='1'>Car4</option>
    <option value='5' data-parentid='1'>Car5</option>
    <option value='6' data-parentid='2'>Car6</option>
    <option value='7' data-parentid='2'>Car7</option>
    <option value='8' data-parentid='2'>Car8</option>
    <option value='9' data-parentid='3'>Car9</option>
    <option value='10' data-parentid='3'>Car10</option>
    <option value='11' data-parentid='3'>Car11</option>
    <option value='12' data-parentid='3'>Car12</option>
</select>

解决方案2:[基于您的原始答案] 解决方案很简单,只需在删除选项之前获取选择值,并在使用.append之后设置选择。

var $subcategory = $('#sub-category');
var selectedOption = $subcategory.val();
var allsuboptions = $subcategory.find('option').remove();
var selectedOptions = allsuboptions.filter(function() {
  return $(this).data('parentid').toString() === $('#category').val().toString();
});
selectedOptions.appendTo('#sub-category');
$subcategory.val(selectedOption);
<select id="category">
  <option value='1'>Categroy 1</option>
  <option value='2'>Categroy 2</option>
  <option value='3'>Categroy 3</option>
</select>
<select id="sub-category">
  <option value='1' data-parentid='1'>Car1</option>
  <option value='2' data-parentid='1'>Car2</option>
  <option selected='selected' value='3' data-parentid='1'>Car3</option>
  <option value='4' data-parentid='1'>Car4</option>
  <option value='5' data-parentid='1'>Car5</option>
  <option value='6' data-parentid='2'>Car6</option>
  <option value='7' data-parentid='2'>Car7</option>
  <option value='8' data-parentid='2'>Car8</option>
  <option value='9' data-parentid='3'>Car9</option>
  <option value='10' data-parentid='3'>Car10</option>
  <option value='11' data-parentid='3'>Car11</option>
  <option value='12' data-parentid='3'>Car12</option>
</select>

答案 2 :(得分:2)

您未看到的是“已选择”属性与“已选择”属性之间的区别。 如果你把它放在你的代码的末尾,你可以看到它:

// Attribute
console.log( $("#sub-category").find("[selected]").val() );
// Property
console.log( $("#sub-category").find(":selected").val() );

您的值为“3”的选项具有所选属性,但不具有属性,而值为“4”的选项则相反。

每当您在select中添加选项时,您必须重新选择所需的选项:

$("#sub-category").find("[selected]").prop("selected", true);

答案 3 :(得分:2)

Firefox选择最后一个元素。这种行为可能是正确和可解释的。为了理解,请记住以下几点:

  1. jQuery append和remove方法在场景后面逐个处理元素。
  2. 应使用相应的属性检索或设置输入元素的当前状态。
  3. 预期行为(Firefox)

    如示例中所示,从select元素中删除所有选项的工作方式如下:

    1. Car1被移除(Car3保持被选中)
    2. Car2被移除(Car3保持被选中)
    3. Car3被移除。由于这是所选元素,因此删除它将导致下一个元素被选中
    4. Car4已被删除。由于这是所选元素,因此删除它将导致下一个元素被选中
    5. 这将重复,直到所有选项从DOM移动到内存。此时,选项将具有以下属性:

      // allsuboptions.each(function() { console.log(this.value, this.selected); });
      
      value:  1, selected: false
      value:  2, selected: false
      value:  3, selected: true
      value:  4, selected: true
      ...
      value: 12, selected: true
      

      selected = true有3个选项。将选项添加回select元素时,浏览器会将最后选择的元素设置为所选元素。

      Internet Explorer和Chrome

      虽然逐个删除选项,但这两个浏览器不会立即更新所选元素(它们可能等待JavaScript执行完成)。这会导致以下差异:

      • 当删除当前选定的选项时,Internet Explorer不会立即选择下一个选项。因此,删除的选项仅包含一个选定元素。

      • Chrome似乎立即在删除当前选定的选项时选择下一个选项,但它只执行一次。因此,删除的选项包含两个选定的元素。

      为了证明关于立即和延期更新的观点,这里有一个小提琴包含:

      1. 原始代码
      2. 每次删除选项时强制浏览器更新select元素的变体
      3. http://jsfiddle.net/salman/j3oh6s3a/9/

        <强>解决方案

        正如其他答案中所建议的那样,正确的解决方法是在删除选项之前使用引用当前所选选项的变量。类似的东西:

        var $selectedOption = $("#sub-category option").filter(function() {
            return this.selected;
        });
        

        重新插入选项后,您可以检查是否已添加该元素并再次选择它:

        if ($selectedOption.parent().length) {
            $selectedOption.prop("selected", true);
        }
        // or
        $("#sub-category option").filter($selectedOption).prop("selected", true);
        

答案 4 :(得分:0)

您的脚本正在执行您创建的操作。

选择car4的原因是因为

<option selected='selected' value='3' data-parentid='1'>Car3</option>
最初选择了

,然后您appending parentid ='1'到导致car4成为新选择的值。

这个脚本的目的是什么?