php - MySQL/PHP/JS 动态填充下拉菜单

标签 php javascript mysql html mysqli

我正在开发基于数据库/网络的前端,但遇到了一个问题。首先,我有一个带有包含契约(Contract)列表的下拉菜单的表单。选择契约(Contract)后,我希望与该契约(Contract)相关的工作(从 MySQL 数据库中获取)填充第一个下拉菜单下方的第二个下拉菜单。

我本来可以将所有信息放在一个菜单中,但 8000 个条目的下拉菜单有点笨拙。

我的 PHP 和 HTML 勉强过得去,但对于我的目的来说已经足够了,然而我的 ECMA 经验仅限于 Flash MX 中的一点 ActionScript,这是很久以前的事了。 我想尽可能避免使用第三方 JS 库(例如 jQuery),并且我不介意编写更多代码。我只需要知道这是否可行,并朝着正确的方向努力。

我现在闭嘴,这是获取契约(Contract) ID(和关联的客户端)的表单,以及不完整的工作菜单。

<select name='idcontract' onchange=''> 
<!--fetch/display contracts/clients-->
    <?php
        include 'sqldb.php';
        $cntqres = mysqli_query($dbc, 'SELECT * FROM contract');
        while ($cntrow = mysqli_fetch_array($cntqres))
        {
            $cliqres = mysqli_query($dbc, "SELECT * FROM client WHERE idclient = '$cntrow[idclient]'");
            while ($clirow = mysqli_fetch_array($cliqres))
            {
                echo "<option value='$cntrow[idcontract]'>$cntrow[idcontract] $clirow[name]</option>";
            }
        }
    ?>
</select>
<select name='idjob'>
    <option value='NULL'>Please select a contract</option>
<!--here goes the magical piece of code I don't know how to write-->
</select>

如有任何帮助,我们将不胜感激。

编辑:

这是 FeatherAJAX 调用的 PHP :

<?php
    include 'sqldb.php';
    $cnt = mysqli_real_escape_string($dbc, $_GET['cnt']);
    $sql = "SELECT * FROM job WHERE idcontract='$cnt' ORDER BY job.idjob";
    $jqres = mysqli_query($dbc, $sql);
    $i = 1;
    while (($jrow = mysqli_fetch_array($jqres)) && ($i < count($jrow)))
    {
        echo "idjob=><option value='$jrow[idjob]' id='$jrow[idjob]'>Job-$i $jrow[part_desc]</option>";
        $i++;
    }
?>

最佳答案

首先,您可能想要重写生成合约选项的代码块。循环查询结果并为每条记录执行另一个查询是低效的。根据您的查询,您也许可以使用此代码,它执行单个查询,然后基于该查询生成选项。 (我不得不在 ORDER 子句中使用虚构的列名。一般来说,您应该始终对记录集进行排序,以便结果具有确定的顺序——即使您不关心该顺序是什么。

<select name="idcontract" id="idcontract"> 
<!--fetch/display contracts/clients-->
<?php
include 'sqldb.php';
$clients = mysqli_query($dbc, '         
    SELECT  ct.idcontract, ct.idclient, cl.name
    FROM    contract ct LEFT OUTER JOIN client cl ON ct.idclient = cl.idclient
    ORDER BY ct.contractname, cl.clientname
    ');

while ($client = mysqli_fetch_array($clients)) {
    echo "<option value=\"{$client[idcontract]}\">{$client[idcontract} {$client[name]}</option>";
}
?>
</select>
<select name="idjob" id="idjob">
    <option value="NULL">Please select a contract</option>
</select>

对于您的问题,您要查找的代码实际上并没有出现在该注释所在的位置。您需要的是一个事件处理程序,它响应用户在第一个 SELECT 中选择一个选项;然后它应该获取该选项的值并从服务器请求一组键值对填充到第二个 SELECT 中。

像这样:

document.getElementById('idcontract').onchange = function(event) {
    // grab currently selected value
    var sValue = null;
    for(var i = 0, imax = this.childNodes.length; i < imax; i++) {
        var eOption = this.childNodes[i]; // shorthand
        if(eOption.selected) {
            sValue = eOption.value;
            break;
        }
    }

    if(!sValue) return;

    // get the sub-options for this value
    getSubOptions(sValue, function(XHR) {
        // this code runs once the response comes back from the server
        var aPairs = [];
        var nlJobs = XHR.getElementsByTagName('jobs'); // assumptions #1 & #2: response is XML, includes <job> tag for each job

        // extract key-value pairs from XML
        for(var i = 0, imax = nlJobs.length; i < imax; i++) {
            var xJob = nlJobs[i]; // shorthand
            /*
                assumption #3: <job> tag has "id" property
                assumption #4: job name appears inside <job> tag
                assumption #4.5: you've got an abstraction layer that normalizes XML node interfaces so that "text" and "textContent" are folded into "textContent"
            */
            aPairs.push({ 'key': xJob.getAttribute('id'), 'value': xJob.textContent });
        }

        // given array of key-value pairs, rebuild select box
        var eJobs = document.getElementById('idjob');

        setOptions(eJobs, aPairs);
    });
}

function setOptions(eNode, aPairs) {
    if(!eNode || !eNode.nodeName || eNode.nodeName.toUpperCase() !== 'SELECT') return false;

    // empty SELECT of all options
    while(eNode.firstChild) {
        eNode.removeChild(eNode.firstChild);
    }

    // build up new nodes
    var eOpt = null;
    for(var i = 0, imax = aPairs.length; i < imax; i++) {
        eOpt = document.createElement('OPTION');
        eOpt.value = aPairs[i].key;
        eOpt.appendChild(document.createTextNode(aPairs[i].value));
        eNode.appendChild(eOpt);
    }
    return true;
}

当然,这缺少了一个重要部分:您需要某种 AJAX 抽象层。你不需要从框架中获取它,一个好的库可以少于 50 行代码(例如,在 quirksmode.org 上查看 PPK 的 ajax 脚本),但你绝对需要一些东西。该层将提供两个好处:(1)跨浏览器兼容性; (2) 语法糖。

例如,上面的代码没有包含getSubOptions的定义。那是因为逻辑会根据 AJAX 抽象提供的接口(interface)而有所不同。不过,我们的想法是,您将针对您编写的脚本执行 GET 请求,该脚本接受参数并返回满足该请求的数据。在上面的代码中,我假设您编写的脚本将返回格式正确的 XML 数据,并使用 MIME 类型来标识它。或者,您可以使用 JSON(或 JSONP)、纯文本(例如 CSV 样式数据),甚至是您将直接插入到页面中的原始 HTML。

使用完整框架的好处是它们都提供了进行 DOM 操作的便捷方式(即又是语法糖)。

底线:您完全可以通过自主开发的方法来做到这一点(我很自豪地说我自己已经做到了)。但这将花费更长的时间——不仅因为它不那么方便,还因为您必须重新发明轮子 === 查找和修复代码中的错误,而不是利用某些库中经过良好测试的核心组件。

编辑:如果您想使用 JSON 而不是 XML 作为数据交换格式,您可以像这样修改传递给 getSubOptions 的响应处理程序:

getSubOptions(sValue, function(XHR) {
     // this code runs once the response comes back from the server
    var aPairs = eval(XHR.responseText); // assumes JSON defines an array of key-value pairs

    // given array of key-value pairs, rebuild select box
    var eJobs = document.getElementById('idjob');

    setOptions(eJobs, aPairs);
});

下面是 JSON 的示例:

[ { key: '1234', value: 'Job #1' },
  { key: '2345', value: 'Job #2' },
  ...
];

在此示例中,JSON 结构方便地反射(reflect)了 setOptions 所需的属性名称;那就是说,keyvalue 看起来很无礼。

如果您打算将 JSON 用于数据,您可能希望将 JSONP 视为更安全的替代方案。真的很像,只是设计模式和上面的匿名回调技术有点不同。

编辑 2:修改响应者的示例代码:

<?php
include 'sqldb.php';
$cnt = mysqli_real_escape_string($dbc, $_GET['cnt']);
$sql = "SELECT * FROM job WHERE idcontract='$cnt' ORDER BY job.idjob";
$jqres = mysqli_query($dbc, $sql);
$i = 1;

// prepare the response
header('Content-Type: text/html');

while (($jrow = mysqli_fetch_array($jqres)) && ($i < count($jrow))) {
    echo "<option value=\"$jrow[idjob]\" id=\"$jrow[idjob]\">Job-$i ${htmlentities(jrow[part_desc])}</option>";
    $i++;
}
?>

关于php - MySQL/PHP/JS 动态填充下拉菜单,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6919772/

相关文章:

php - 如何在 Windows 中无需用户名和密码即可将 Laravel 应用程序与 MySQL 连接

php - 使用 gmail 发送 phpmailer smtp 电子邮件需要很长时间(1.5 秒)

javascript - jQuery 数据表 : Uncaught TypeError: Cannot read property 'length' of undefined

mysql - 我如何从 2 列中减去值,然后在 sequelize js 中应用 max 函数?

php - 在具有变量的类中查询

PHP 使用 Shift_JIS 转换编码

php - Laravel 4 Blade @include 变量

javascript - jQuery 读取非空和可见的文本字段

javascript - css - 有没有办法让 div 与 h1(多行)在同一第二行?

where 子句中未知的 Mysql 别名列