【问题标题】:jQuery option appendTo select moves to next option instead of select onejQuery 选项 appendTo 选择移动到下一个选项而不是选择一个
【发布时间】:2015-01-01 04:58:11
【问题描述】:

http://jsfiddle.net/j3oh6s3a/

由于某些原因,将选项附加到选择标记不会选择 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。

【问题讨论】:

  • 我刚刚检查了您分享的fiddle,它只选择了Car3。我不明白你的问题可能是。
  • 有趣的是它显示了 Car4,但是如果您检查元素并查看代码,则选择了 Car3:&lt;option selected="selected" value="3" data-parentid="1"&gt;Car3&lt;/option&gt;
  • 你运行代码了吗?它正在选择 Car4 吗?我刚刚验证了它
  • 我在您发布的 jsfiddle 中运行代码;然后,不做任何更改,右键单击下拉菜单并单击“检查元素”。 Car4 是显示的选项,但根据代码 Car3 是选择的选项
  • 谁在看这个答案。 @salman 下面给出了一些很好的解释。请检查一下

标签: javascript jquery html select


【解决方案1】:

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

如果您在不同的浏览器上测试小提琴,您会看到所选值发生变化: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,它将是选定的。

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

【讨论】:

  • 这是一个很好的理论。如果所有的实验都得出这些结果,那么我们别无选择,只能接受这个理论。现在,在从选择中删除选项之前,我正在备份所选值并再次设置它。这就是我在项目中解决问题的方式
  • 我找不到任何东西来证明这一点。我会尝试与他们联系,看看他们是否能有所启发。
  • @Srikan 这似乎是目前最好的跨浏览器解决方案。
  • 谁在看这个答案。 @salman 下面给出了一些很好的解释。请检查一下
【解决方案2】:

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

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

当您使用 removeChild 然后 appendChild 将选项添加回来时,属性会保留,但元素的属性不会保留。您可以在此处阅读有关 .prop() vs .attr() 的更多信息。

总而言之,属性是在 HTML 中定义的初始值,浏览器解析后将其设置为元素的属性,但是设置属性并不能保证设置属性。

$(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>

测试结果:

在测试上述 sn-p 时,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>

方案二:[根据你原来的答案]方案很简单,在去掉选项前获取选择值,使用.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>

【讨论】:

    【解决方案3】:

    您看不到的是“选定”属性和“选定”属性之间的区别。 如果您将其放在代码的末尾,您可以看到它:

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

    值为“3”的选项具有 selected 属性,但没有属性,值为“4”的选项相反。

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

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

    【讨论】:

    • 添加这行 $("#sub-category").find("[selected]").prop("selected", true); 代码对我来说适用于所有浏览器。
    • 这很有趣。属性被复制但属性在删除/附加时“丢失”?我需要详细了解属性和属性之间的区别以及它们的工作原理
    【解决方案4】:

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

    1. jQuery append 和 remove 方法在后台一一处理元素。
    2. 应使用相应的属性而不是属性来检索或设置输入元素的当前状态。

    预期行为 (Firefox)

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

    1. Car1 已移除(Car3 仍处于选中状态)
    2. Car2 已移除(Car3 仍处于选中状态)
    3. Car3 被移除。由于这是被选中的元素,删除它会导致下一个元素被选中
    4. Car4 被移除。由于这是被选中的元素,删除它会导致下一个元素被选中

    这将重复,直到所有选项都从 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 似乎立即在当前选择的选项被删除时选择下一个选项,但它只这样做一次。因此,删除的选项包含两个选定的元素。

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

    1. 原代码
    2. 每次删除选项时强制浏览器更新选择元素的变体

    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);
    

    【讨论】:

    • 那么,IE/Chrome 的行为可以被认为是一个错误吗?
    • Chrome 不一致(第一次更改所选项目)因此可能被视为错误。 IE 和 FireFox 各有各的道理。
    【解决方案5】:

    您的脚本正在执行您创建它的目的。

    之所以选择car4,是因为

    <option selected='selected' value='3' data-parentid='1'>Car3</option>
    

    最初被选中,然后你是 appendingparentid='1' 到导致 car4 成为新选择的值。

    这个脚本的目的是什么?

    【讨论】:

    • 已经很晚了,我可能遗漏了什么。什么 parentid='1' 是 OP 附加到哪个值?
    • 这里是这一行return $(this).data('parentid').toString() === $('#category').val().toString();。但我仍然不太确定它的作用:)
    • 以上行验证选项的 data-parentid 是否与类别值匹配。这些选项将被过滤掉。
    猜你喜欢
    • 1970-01-01
    • 2012-07-18
    • 2018-11-30
    • 1970-01-01
    • 2015-06-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多