繁体   English   中英

根据第一和第二个菜单选择填充第三个下拉菜单

[英]Populate third drop down menu based on first & second menu selection

我使用以下代码动态填充三个下拉菜单“project_select”、“hr_select”和“id_select”。

$(document).ready(function() {

  var table = $('#example1').DataTable({
    data: dataSet1,
    orderCellsTop: true,
    columns: [{
        data: "Project_Name"
      },
      {
        data: "ID"
      },
      {
        data: "HR"
      }
    ],
    initComplete: function() {
      this.api().columns([0, 1, 2]).every(function() {
        var column = this;
        var colIdx = column.index();
        var node;
        var select;
        if (colIdx === 0) {
          node = $('#project_select');
          select = $('<select id="project_s" style="width: 20%"><option value=""></option></select>');
        }
        if (colIdx === 2) {
          node = $('#hr_select');
          select = $('<select id="hr_s" style="width: 20%" multiple><option value=""></option></select>');
        }
        if (colIdx === 1) {
          node = $('#id_select');
          select = $('<select id="id_s" style="width: 20%" multiple><option value=""></option></select>');

        }

        select.appendTo($(node).empty())
          .on('change', function() {
            var val = $(this).val();
            if (colIdx === 0) {
              val = $.fn.dataTable.util.escapeRegex(val);
              column.search(val).draw();
              rebuildPositionSelect();
              rebuildIDSelect();
            }
            if (colIdx === 2) {
              const vals = $('option:selected', this).map(function(index, element) {
                return $.fn.dataTable.util.escapeRegex($(element).val());
              }).toArray().join('|');
              column.search(vals.length > 0 ? '^(' + vals + ')$' : '', true, false).draw();
              rebuildIDSelect();
            } else {
              const vals = $('option:selected', this).map(function(index, element) {
                return $.fn.dataTable.util.escapeRegex($(element).val());
              }).toArray().join('|');
              column.search(vals.length > 0 ? '^(' + vals + ')$' : '', true, false).draw();
            }
          });

        column.data().unique().sort().each(function(val) {
          select.append('<option value="' + val + '">' + val + '</option>')
        });

      });


      function rebuildPositionSelect() {
        var select = $('#hr_select select').empty().append('<option value=""></option>');
        var column = table.column(2, {
          search: 'applied'
        });
        column.search('').draw();
        column.data().unique().sort().each(function(val) {
          select.append('<option value="' + val + '">' + val + '</option>');
        });
      }

      function rebuildIDSelect() {
        var select = $('#id_select select').empty().append('<option value=""></option>');
        var column = table.column(1, {
          search: 'applied'
        });
        column.search('').draw();
        column.data().unique().sort().each(function(val) {
          select.append('<option value="' + val + '">' + val + '</option>');
        });
      }

      $('#project_s').select2({
        placeholder: "Select Project:",
        allowClear: true,
        width: 'resolve'
      })
      $('#hr_s').select2({
        placeholder: "Select Hr(s):",
        closeOnSelect: false,
        allowClear: true,
        tags: true,
        width: 'resolve'
      });
      $('#id_s').select2({
        placeholder: "Select ID:",
        closeOnSelect: false,
        allowClear: true,
        tags: true,
        width: 'resolve'
      });


    }
  });

});

目前,“hr_select”和“id_select”菜单填充了基于用户在“project_select”中的单一选择的值。 我正在努力根据用户在“hr_select”中的多项选择来进一步填充“id_select”菜单。

错误示例:用户选择项目 A 和小时 0、10、20。“id_select”菜单应仅填充值“Spike”。 菜单当前正在填充“Spike”和“Hit”的值。

关于如何修复我的函数rebuildIDSelect以修复此错误的任何想法?

https://jsfiddle.net/dfahsjdahfsudaf/nL6q21g9/63/

谢谢。

编辑:“id_select”菜单应该只填充值 Spike,因为当您过滤项目 A 和小时 0、10、20 的整体数据表时。Spike 是表中为所有这些值列出的唯一值。 命中仅与项目 A 和小时 0、10 相关联。因为命中未在表中列为 20 小时的行。当用户选择小时 0、10 时,它不应显示在“id_select”菜单中,并且20 来自“hr_select”菜单。

逻辑要求的是基于所选 HR 值的 ID 值的交集。 这比仅使用0 or 10 or 20复杂得多,因为它需要您考虑整个列中的数据。

下面的方法不是一个完整的解决方案 - 至少有一个我会在最后提到的问题。 另外,我怀疑可能有一种更有效的方法来实现以下内容,但这应该向您展示一种方法:

  1. 构建一个对象,该对象显示 Project 和 HR 值的每个组合的 ID 值集。

这是执行此操作的代码(使用 Fiddle 中的示例代码):

hrToIdMapper = {};

// builds an object which uses HR for the keys and 
// an array of IDs for each HR:
this.api().rows().every(function() {
  var row = this;
  let key = row.data().Project_Name + '-' + row.data().HR;
  let val = row.data().ID;
  if ( hrToIdMapper.hasOwnProperty(key) ) {
    // could be optimized to avoid array duplicates:
    hrToIdMapper[key].push( val ); 
  } else {
    hrToIdMapper[key] = [ val ];
  }
});

由此创建的数据是:

{
  "A-0": [ "Hit", "Spike" ],
  "A-10": [ "Hit", "Spike" ],
  "A-20": [ "Spike" ],
  "B-0": [ "Kick" ],
  "B-10": [ "Kick" ],
  "B-20": [ "Kick" ]
}

我们稍后将使用这些数据来帮助确定我们需要的正确结果的交集。

  1. 将逻辑添加到if (colIdx === 2)部分以构建选定值的数组。

逻辑:

const intersectInputs = $('option:selected', this).map(function(index, element) {
  return $(element).val();
}).toArray().map(x => proj + '-' + x);

因此,例如,如果您选择了 Project = "A" 和 HR = "0, 10, 20",则数组将如下所示:

[ "A-0", "A-10", "A-20" ]

这基本上是一个键数组,我们可以在我们在步骤 1 中创建的数据结构中看到它。

  1. 使用上面显示的两种数据结构来构建我们需要的“交集结果”:
function buildIntersection(vals) {
  var arrs = [];

  vals.forEach((val) => { 
    arrs.push( hrToIdMapper[val] );
  } );

  // iterate over each array:
  var results = arrs.reduce(function(prev, curr, idx, arr) {
    // find the overall intersection across all these arrays:
    return prev.filter(value => curr.includes(value))
  });

  return results;
}

这从步骤 2 中获取我们的数据数组,对于该数组中的每个项目,它会从步骤 1 中找到相关的“Hit/Spike/Kick”数组。

对于这些“Hit/Spike/Kick”数组中的每一个,它然后找到交集(即存在于所有“Hit/Spike/Kick”数组中的那些值。

在我的示例中,结果是一个仅包含“Spike”的新数组:

[ "Spike" ]
  1. 我们可以将此值传递给rebuildIDSelect()函数,以确保 ID 列中仅显示相关值。

这是一个演示:

 var dataSet1 = [{ "Project_Name": "A", "ID": "Hit", "HR": "0", }, { "Project_Name": "A", "ID": "Hit", "HR": "10", }, { "Project_Name": "A", "ID": "Spike", "HR": "0", }, { "Project_Name": "A", "ID": "Spike", "HR": "10", }, { "Project_Name": "A", "ID": "Spike", "HR": "20", }, { "Project_Name": "B", "ID": "Kick", "HR": "0", }, { "Project_Name": "B", "ID": "Kick", "HR": "10", }, { "Project_Name": "B", "ID": "Kick", "HR": "20", } ]; $(document).ready(function() { var table = $('#example1').DataTable({ data: dataSet1, orderCellsTop: true, columns: [{ data: "Project_Name" }, { data: "ID" }, { data: "HR" } ], initComplete: function() { hrToIdMapper = {}; // builds an object which uses HR for the keys and // an array of IDs for each HR: this.api().rows().every(function() { var row = this; let key = row.data().Project_Name + '-' + row.data().HR; let val = row.data().ID; if ( hrToIdMapper.hasOwnProperty(key) ) { // could be optimized to avoid array duplicates: hrToIdMapper[key].push( val ); } else { hrToIdMapper[key] = [ val ]; } }); this.api().columns([0, 1, 2]).every(function() { var column = this; var colIdx = column.index(); var node; var select; if (colIdx === 0) { node = $('#project_select'); select = $('<select id="project_s" style="width: 20%"><option value=""></option></select>'); } if (colIdx === 2) { node = $('#hr_select'); select = $('<select id="hr_s" style="width: 20%" multiple><option value=""></option></select>'); } if (colIdx === 1) { node = $('#id_select'); select = $('<select id="id_s" style="width: 20%" multiple><option value=""></option></select>'); } select.appendTo($(node).empty()) .on('change', function() { var val = $(this).val(); if (colIdx === 0) { val = $.fn.dataTable.util.escapeRegex(val); column.search(val).draw(); rebuildPositionSelect(); rebuildIDSelect([]); } if (colIdx === 2) { var proj = $("#select2-project_s-container").text(); const vals = $('option:selected', this).map(function(index, element) { return $.fn.dataTable.util.escapeRegex($(element).val()); }).toArray().join('|'); column.search(vals.length > 0 ? '^(' + vals + ')$' : '', true, false).draw(); const intersectInputs = $('option:selected', this).map(function(index, element) { return $(element).val(); }).toArray().map(x => proj + '-' + x); let intersect = buildIntersection(intersectInputs); rebuildIDSelect(intersect); } else { const vals = $('option:selected', this).map(function(index, element) { return $.fn.dataTable.util.escapeRegex($(element).val()); }).toArray().join('|'); column.search(vals.length > 0 ? '^(' + vals + ')$' : '', true, false).draw(); } }); column.data().unique().sort().each(function(val) { select.append('<option value="' + val + '">' + val + '</option>') }); }); function buildIntersection(vals) { var arrs = []; vals.forEach((val) => { arrs.push( hrToIdMapper[val] ); } ); var results = arrs.reduce(function(prev, curr, idx, arr) { return prev.filter(value => curr.includes(value)) }); return results; } function rebuildPositionSelect() { var select = $('#hr_select select').empty().append('<option value=""></option>'); var column = table.column(2, { search: 'applied' }); column.search('').draw(); column.data().unique().sort().each(function(val) { select.append('<option value="' + val + '">' + val + '</option>'); }); } function rebuildIDSelect(intersect) { var select = $('#id_select select').empty().append('<option value=""></option>'); var column = table.column(1, { search: 'applied' }); if (intersect.length === 0) { column.search('').draw(); column.data().unique().sort().each(function(val) { select.append('<option value="' + val + '">' + val + '</option>'); }); } else { intersect.forEach((val) => { select.append('<option value="' + val + '">' + val + '</option>'); } ); column.search('^(' + intersect.join('|') + ')$', true, false).draw(); } } $('#project_s').select2({ placeholder: "Select Project:", allowClear: true, width: 'resolve' }) $('#hr_s').select2({ placeholder: "Select Hr(s):", closeOnSelect: false, allowClear: true, tags: true, width: 'resolve' }); $('#id_s').select2({ placeholder: "Select ID:", closeOnSelect: false, allowClear: true, tags: true, width: 'resolve' }); } }); });
 <!doctype html> <html> <head> <meta charset="UTF-8"> <title>Demo</title> <script src="https://code.jquery.com/jquery-3.5.1.js"></script> <script src="https://cdn.datatables.net/1.10.22/js/jquery.dataTables.js"></script> <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.22/css/jquery.dataTables.css"> <link rel="stylesheet" type="text/css" href="https://datatables.net/media/css/site-examples.css"> <link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" /> <script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script> </head> <body> <div style="margin: 20px;"> <div> <span>Project: </span> <span id="project_select"></span> <span> HR: </span> <span id="hr_select"></span> <span>ID: </span> <span id="id_select"></span> </div> <br><br> <table id="example1" class="display dataTable cell-border" style="width:100%"> <thead> <tr> <th>Project_Name</th> <th>ID</th> <th>HR</th> </tr> </thead> </table> </div> </body> </html>

最终结果是这样的:

在此处输入图片说明


不完整的演示

剩下的一个问题(可能还有更多!):一旦用户做出选择并创建了最终结果,如屏幕截图所示,用户可以选择然后删除 ID 下拉列表中的“Spike”标签。 目前,这将导致重新显示不需要的“命中”行。

处理这样的边缘情况可能会产生很多额外的复杂性。

最后一点,这只是我个人的意见:总的来说,无论如何,如果不清楚为什么他们会看到他们看到的结果,它最终可能会给用户带来混乱的体验。 如果下拉逻辑变得过于复杂,用户可能会怀疑他们所看到的内容的正确性。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM