我正在开发基于数据库/网络的前端,并遇到了一个问题。首先,我有一个带有下拉菜单的表单,其中包含合同列表。选择合同后,我希望与该合同相关的工作(从MySQL数据库获取)填充第一个下方的第二个下拉菜单。
我会在一个菜单中获得所有信息,但是8000条目下拉菜单有点笨拙。
我的PHP和HTML几乎无法通过,但足以达到我的目的,但是我的ECMA体验仅限于Flash MX中的一些ActionScript,很多年前。 如果可能的话,我想避免使用第三方JS库(例如jQuery),我不介意编写更多代码。我只需要知道这是否可行,并且朝着正确的方向发展。
我现在会闭嘴,下面是获取合同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++;
}
?>
答案 0 :(得分:2)
首先,您可能想要重写产生合同选项的代码块。循环查询结果并对每个记录执行另一个查询是低效的。根据您的查询,您可以使用此代码,该代码执行单个查询,然后根据该代码生成选项。 (我必须在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抽象提供的接口而有所不同。但是,您的想法是,您将针对您编写的接受参数并返回满足该请求的数据的脚本执行GET请求。在上面的代码中,我假装您编写的脚本将返回正确格式的XML数据,其MIME类型标识它。或者,您可以使用JSON(或JSONP),直接文本(例如CSV样式数据),甚至是刚刚插入页面的原始HTML。
使用完整框架的好处是它们都提供了方便的DOM操作方法(即再次使用语法糖)。
底线:你绝对可以用自己开发的方法做到这一点(我很自豪地说我自己做过)。但这需要更长的时间 - 不仅仅是因为它不太方便,还因为你必须重新发明轮子===在你的代码中找到并修复bug,而不是利用一些库中经过充分测试的核心组件。 / p>
编辑:如果你想使用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结构方便地镜像setOptions
所期望的属性名称;这就是说,key
和value
似乎非常无害。
如果您已开始使用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++;
}
?>