设置 PHP 数组以使用从 Json 对象创建的下拉列表

Set PHP array to work with dropdown list created from Json object

我已经坚持了几天了,需要一些专家建议!

所以,作为一个 personal/learning 项目,我正在为我朋友的 D&D 游戏制作一个有趣的小东西 'character relationship tracker'。有了这个,我有一个虚拟地牢大师的数据库 table 以及他们是 运行 的游戏,用于测试代码。我正在尝试创建一个级联下拉列表,该列表由 PHP 的混合生成并编码为 JSON 作为提交新字符表单的一部分。有用!除了,在包含选项信息的数据库中,有些在 DM 的列表中只有一个游戏,而另一些则在同一 DM 的列表中有多个游戏。对于那些单身人士,JS 将每个字母都列为不同的选择,而不仅仅是单个完整选项。我曾尝试重新制作 PHP 两次以尝试解决此问题,并通过一些 JS 尝试进行了洗牌,但无济于事。这些更改要么完全破坏了代码,要么导致没有任何更改。

This fiddle is what it is doing with my best attempt

至于实际代码:

HTML

<div class="selectdiv">
        <select name="chargm" id="charadm" onChange="chgm(this.value);" required>
            <option value="" selected="true" disabled>Game Master</option>
            <?php foreach ($gameMasters as $masterName) { echo "<option value='". $masterName . "'>" . $masterName . "</option>"; } ?>
        </select>
    </div>
    <div class="selectdiv">
        <select name="chargame" id="chargm" required>
            <option value="" selected="true" disabled>Game Name</option>
        </select>
    </div>

这是 PHP(我知道它超级混乱和多余,但出于某种原因我无法让它以任何其他方式工作并且它能正常工作?)

//database connection stuff
$sqls = "SELECT * FROM datgames;";
$stmts = mysqli_query($conn, $sqls);
$resultcheck = mysqli_num_rows($stmts);
$gameMasters = array(); //create empty array of game masters.
$gameData = array(); //set up game list data array

//check if db can be read before contiuning.
if($resultcheck > 0){
  while($row = mysqli_fetch_assoc($stmts)){ //while there are rows, add to array
    $gameMasters[] = $row["datgamDM"]; //fill the gameMasters array with all gm's
    $gmdm = $row["datgamDM"]; //define gmdm as the game master of the row

    //copy existing info in gameData to preserve data
    $anotm = $gameData;

    //clear game data to reset it to avoid repeats
    unset($gameData);

    //create the key => value pair
    $tmpar[$gmdm] = $row["datgamName"];

    //merge the temp arrays and apply them to the global array
    $gameData = array_merge_recursive($anotm, $tmpar);

    //clear the temporary arrays to avoid repeats
    unset($anotm);
    unset($tmpar);
  }
}else{ exit(); } //if db can't be reached, break the code.

$gameMasters = array_unique($gameMasters);

//print_r($gameData); //making sure the array is right. this line is removed once this is working

以及当前使用此循环 PHP 的确切 JSON 输出

{
    "Reid":[
        "Curse of Strahd",
        "ufkck"],
    "bob":[
        "Curse of Strahd",
        "fffs"]
    ,"jomama":"blaal",
    "taco":"salff"
};

和 JS

var list = <?php echo json_encode($gameData); ?>;

    function chgm(value) {
      if (value.length == 0) document.getElementById("chargm").innerHTML = "<option></option>";
      else {
        var games = "";
        for (categoryId in list[value]) {

          games += "<option>" + list[value][categoryId] + "</option>";
        }
        document.getElementById("chargm").innerHTML = games;
      }
    }

问题简而言之:我在 PHP(很可能是原因)或 Javascript 中做错了什么导致了单个对象组拆分为字母而不是显示完整单词作为第二个下拉选项的唯一选项?

或者更确切地说,我如何让 PHP 使单个条目显示为多维数组,同时保留密钥以便它在 JSON 对象中显示为数组?

别把我的评论当回事 // 是你的旧代码 /// 是我的评论

var list = {
    "Reid": ["Curse of Strahd", "uuck"],
    "bob": ["Curse of Strahd", "fffts"],
    "jomama": "blaal",
    "taco": "salff"
  };


  function chgm(value) {
  // if (value.length == 0) document.getElementById("chargm").innerHTML = "<option></option>";
  /// do not use == use ===
  /// avoid innerHTML
  var node = document.getElementById("chargm");
  var option;
  if (!value) {
      node.appendChild( document.createElement('options') );
          return;
  } 
    //else {
    /// pls do not append to a string!
    /// imagine you have 7000 values, the OS have everytime to get the string size AND 
    /// (re-)allocate new memory!!
    // var games = "";
    /// var games = []; // use an array instead of!
    /// use of instead of in, if you want to use in, you have to make sure if list.hasOwnProperty(value) is true
      // for (gameMas in list[value]) {
      /// for (var gameMas of Object.keys(list)) {
    /// but we know already what we are looking for, so let's check for that:
    if (list.hasOwnProperty(value)) {
        // ok we have now other new values, but what's with the other ones?
        // lets kill everything for lazyness
      while(node.firstChild && node.removeChild(node.firstChild));
      /// reset the header
         node.appendChild( document.createElement('option') ).innerText = 'Game / RP Name';
      // games += "<option>" + list[value][gameMas] + "</option>";
      /// your example array is inconsistent, so we have to check for the type
      if (!Array.isArray(list[value])) {
        /// with an array do this:
        /// games.push('<option>' + list[gameMas] + '</option>');
        
        option = node.appendChild( document.createElement('option') );
        option.innerText = list[value];
        option.value = list[value];
        return;
      }
      /// else
      for (var v of list[value]) {
        /// with an array do this:
        /// games.push('<option>' + list[gameMas][value] + '</option>');
        option = node.appendChild( document.createElement('option') );
        option.innerText = v;
        option.value = v;
      } 
    }
      // document.getElementById("chargm").innerHTML = games;
      /// with an array do this:
      /// document.getElementById("chargm").innerHTML = games.join('');
  }
<select name="chargm" id="charadm" onChange="chgm(this.value);">
  <option value="" selected="true" disabled="">DM/Admin</option>
  <option value="Reid">Reid</option>
  <option value="bob">bob</option>
  <option value="jomama">jomama</option>
  <option value="taco">taco</option>
</select>
<select name="chargame" id="chargm">
  <option value="" selected="true" disabled>Game / RP Name</option>
</select>

使用 array_merge_recursive() 的问题在于它在创建深度时会产生不一致的结构。

例如,如果有多个元素,第一级键包含一个索引子数组,但当只有一个元素存在时,在第一级创建一个关联数组。 I explain this here and provide a simple demonstration.

使用 foreach() 可以立即遍历 mysqli 的 query() 的结果集,因此我推荐使用简洁的技术来设置直观的关联数组访问。

$result = [];
foreach ($conn->query("SELECT datgamDM, datgamName FROM datgames") as $row) {
    $result[$row["datgamDM"]][] = $row["datgamName"];
}
exit(json_encode($result));

这样,您就有了一个一致的结构 -- 索引数组的关联数组。换句话说:

{
    "Reid":["Curse of Strahd","ufkck"],
    "bob":["Curse of Strahd","fffs"],
    "jomama":["blaal"],
    "taco":["salff"]
}

然后生活只会变得更轻松。你只需要像这样迭代:

for (index in list[value]) {

至于您用来生成 select/option 标记的技术——我不会那样做,有多种方法可以做到,Whosebug 上有大量页面解释这些选项适合你。

我通常不喜欢 UI 提供表单说明或标签作为字段的顶部选项。我建议你给你的表单字段 <label>s 以便选项只包含 real 选项。


作为一个完全不同的替代方案,如果您不想每次用户进行 select 离子更改时都继续修改 DOM,您可以打印所有次级 select 预加载选项的字段,然后将它们全部“隐藏”。然后当用户更改主要 select 字段时,仅“显示”具有相关 id 的字段。这当然会创建更多 html 标记(根据您的数据量,这可能有吸引力也可能没有吸引力),但它大大降低了 javascript 代码的复杂性,因为所有动态处理都是在页面加载。如果有一天,您想将主 select 字段设为“多 select”,那么具有可切换的辅助字段会很好地工作。 ...“课程用马”等等。