在同一页面上提交表单时如何预填充下拉列表?

Posted

技术标签:

【中文标题】在同一页面上提交表单时如何预填充下拉列表?【英文标题】:How to pre-populate drop down list when form submitted on same page? 【发布时间】:2012-10-24 10:09:12 【问题描述】:

我使用带有下拉列表的表单制作了一个过滤器。过滤器用于过滤来自 mysql 数据库的结果。表单与结果在同一页面上处理。我想让过滤器下拉列表在过滤结果后保留过滤器参数。

我过去曾通过使用会话来完成此操作,但那是我使用另一个页面来处理查询的时候。我试图应用同样的理论,但它不起作用。我搜索了这个网站以及谷歌,我只找到了与一个单独的页面相关的答案。

目前,我拥有的代码只会在提交两次后才预填充表单。第一次提交时显示默认设置“选择...”

以下是我的代码的相关部分:

session_start();
if(isset($_SESSION['submitted_filter_values']))

extract($_SESSION['submitted_filter_values']);


<form action="#filter" method="post" name="filter">
<table>

<tr>
<td>
<select name="prefix">
<option value="">Select...</option>
<option <?php if(isset($prefix) && $prefix == "PDM")echo "selected=\"selected\""; ?> value="PDM">PDM</option>
<option <?php if(isset($prefix) && $prefix == "TB")echo "selected=\"selected\""; ?> value="TB">TB</option>
<option <?php if(isset($prefix) && $prefix == "JNL")echo "selected=\"selected\""; ?> value="JNL">JNL</option>
</select>
</td>
</tr>

<tr align="center">
<td colspan="2"><input type="submit" class="btn_150x30" name="submit" value="Filter Results"></td>
</tr>

</table>
</form>

$_SESSION['submitted_filter_values'] = $_REQUEST;

我尝试将会话变量放在不同的位置,但没有奏效。我认为刷新页面可能会起作用,但后来我认为它会像我两次提交表单时一样有效地删除过滤器。需要注意的有趣的一点是,它非常一致,因为它在我每第二次提交时都会正常工作,所以每一次奇数提交它都不会填充,而每一个偶数提交它都会填充。

【问题讨论】:

您说您希望在 POSTs 中保留 select 元素 value 字段,但您是否也真的希望保留该设置会话范围? 你在哪里声明 $prefix 变量? @didierc 你提出了一个奇妙的观点。我不一定需要它在会话范围内,我显然刚刚学到了为什么我不尝试让某些东西在不同的应用程序上工作。 【参考方案1】:

在意识到会话对我的应用程序来说不是一个好主意后,因为它只在一个页面上使用,而不是在整个站点上使用,我采取了一种新的方法来解决这个问题。

在我的过滤器顶部,每个选项都有这个:

if(isset($_POST['prefix']))
    
    $prefix = $_POST['prefix'];
    

然后在我的下拉列表中,每个选项都有这个:

<option <?php if(isset($prefix) && $prefix == "PDM")echo "selected=\"selected\""; ?> value="PDM">PDM</option>

【讨论】:

【参考方案2】:

这是您遇到的请求和会话问题。如果我按照你的脚本处理对了,你有以下情况:

首次提交时,会话submitted_filter_values 未设置。您将看到默认条目,$prefix 仍未设置。

在第二次提交时,然后设置会话submitted_filter_values输出选择标签之后。由于该顺序,您仍然会看到默认条目。

在第三次提交时,您将看到第二次提交的过滤器。

在第四次提交时,您将看到第三次提交的过滤器。以此类推。

如果您不提交而只是通过 GET 请求,则该值仍然存在,但是您还将会话 submitted_filter_values 设置回默认值,因为 $_REQUEST 不再包含 prefix

看到这个顺序也有助于改变脚本。一条经验法则是在脚本之上处理输入变量(设置与否)。虽然编写 @Chris 已经为此提供了代码 - 我会做的有点不同,但他的例子展示了它是如何工作的。

我首先会在顶部定义过滤器,使用请求和会话逻辑一个接一个地处理它们,然后输出表单。这样做的好处是您可以更改顶部的数据逻辑和输出中的输出逻辑。

<?php
session_start();

/**
 * define your filter(s)
 */
$filters = array(
    'prefix' => array(
        'value' => null,
        'list' => array('PDM', 'TB', 'JNL')
    )
);

$filtersSessionName = 'submitted_filter_values';

/**
 * process the state of your filter(s) with request input and
 * session state
 */
foreach($filters as $name => $filter) 

    // does request has filter value set?
    if (isset($_REQUEST[$name])) 
        $requestValue = $_REQUEST[$name];
        // does it validate?
        if (in_array($requestValue, $filter['list'])) 
            $filter['value'] = $requestValue;
            $_SESSION[$filtersSessionName][$name] = $requestValue;
            continue;
        
    

    // does the session has filter value set?
    if (isset($_SESSION[$filtersSessionName][$name])) 
        $sessionValue = $_SESSION[$filtersSessionName][$name];
        // does it validate?
        if (in_array($sessionValue, $filter[$list])) 
            $filter['value'] = $sessionValue;
            continue;
        
    



/**
 * output the filter(s) in the form
 */
?>

<form action="#filter" method="post" name="filter">
    <table>
        <?php foreach($filters as $name => $filter)  ?>
            <tr>
                <td>
                    <select name="<?php echo $name; ?>">
                        <option value="">Select ...</option>
                        <?php foreach($filter['values'] as $label) 
                            $selected = $filter['value'] === $label;
                        ?>
                            <option <?php if ($selected)  echo 'selected="selected"'; ?> value="<?php echo $label ?>">
                                <?php echo $label ?>
                            </option>
                        <?php  ?>
                    </select>
                </td>
            </tr>
        <?php  # foreach filters ?>
        <tr align="center">
            <td colspan="2"><input type="submit" class="btn_150x30" name="submit" value="Filter Results"></td>
        </tr>
    </table>
</form>

这可以通过对过滤器列表使用键/值对来进一步改进,以便过滤器的标签可以与提交的值不同。此外,$_REQUEST 变量也可以加上前缀,这样过滤器的名称就会与请求变量一起命名,就像它已经在会话中完成一样。

【讨论】:

老实说,你的帖子让我意识到我对这种语言有多少了解。我会很尴尬地向你展示我是如何制作我的过滤器的!是的,它有效,但我现在肯定它非常低效。我有更多的过滤器选项,我现在确信我需要从不同的(阅读:更容易)的角度来看待这个问题。 +1 提供一些优秀的信息,谢谢:)【参考方案3】:

试试这个:

<?php 
    session_start();

    if(isset($_POST['prefix']))
        // if the form has been posted use it
        $prefix = $_POST['prefix']; // <------ RUN SOME VALIDATION HERE!!!!!!!
        $_SESSION['submitted_filter_values'] = $prefix; // update the session var

    elseif(isset($_SESSION['submitted_filter_values']))
        // if the form hasn't been posted then look in the $_SESSION
        $prefix = $_SESSION['submitted_filter_values']; // <------ RUN SOME VALIDATION HERE (trust no one!)!!!!!!!
    



?>
    <form action="#filter" method="post" name="filter">
        <table>

            <tr>
                <td>
                    <select name="prefix">
                        <option value="">Select...</option>
                        <option<?php if($prefix == "PDM")echo " selected=\"selected\""; ?> value="PDM">PDM</option>
                        <option<?php if($prefix == "TB")echo " selected=\"selected\""; ?> value="TB">TB</option>
                        <option<?php if($prefix == "JNL")echo " selected=\"selected\""; ?> value="JNL">JNL</option>
                    </select>
                </td>
            </tr>
            <tr align="center">
                <td colspan="2">
                    <input type="submit" class="btn_150x30" name="submit" value="Filter Results" />
                </td>
            </tr>

        </table>
    </form>

【讨论】:

我有几个字段充当过滤器,我没有将它们全部发布,因为我没想到答案会朝着这个方向发展。另外,我通常会发布太多代码,并且会被某人编辑掉,所以我试图避免这种情况。现在我确信我应该从头开始,根本不使用会话,就像我在上面的 cmets 中所说的那样,我认为我不应该尝试将此代码应用于此应用程序。对于这个应用程序,发布的信息不会超出这一页,所以现在一个会话似乎......嗯......愚蠢。无论如何,非常感谢您提供信息丰富的回复。 +1 :)【参考方案4】:

您需要更改处理$REQUEST 结果的方式。

<?php
session_start();
if (isset($REQUEST))  // do we have a submitted request?
         // yes -> save it in session

    $_SESSION['submitted_filter_values']['prefix'] = $REQUEST['prefix'];
    $prefix = $REQUEST['prefix'];

 else   // no -> try to retrieve it from the session

   if(isset($_SESSION['submitted_filter_values']))
   
      $prefix = extract($_SESSION['submitted_filter_values']['prefix']);
   


?>

<form action="#filter" method="post" name="filter">
<table>

<tr>
<td>
<select name="prefix">
<option value="">Select...</option>
<option <?php if(isset($prefix) && $prefix == "PDM")echo "selected=\"selected\""; ?> value="PDM">PDM</option>
<option <?php if(isset($prefix) && $prefix == "TB")echo "selected=\"selected\""; ?> value="TB">TB</option>
<option <?php if(isset($prefix) && $prefix == "JNL")echo "selected=\"selected\""; ?> value="JNL">JNL</option>
</select>
</td>
</tr>

<tr align="center">
<td colspan="2"><input type="submit" class="btn_150x30" name="submit" value="Filter Results"></td>
</tr>

</table>
</form>

关于extract,将它与不受信任的输入(如 $REQUEST 数组)一起使用是非常糟糕的做法,其中可能包含不需要的值。想象一下有人伪造了一个指向该页面的 URL,其中一些参数覆盖了脚本中的某些值,因为您使用 $REQUEST,您将提取这些值并可能用危险值覆盖您的变量。 这就是为什么我只从 $REQUEST 数组中复制 prefix 值。

【讨论】:

感谢您提供有关同时使用extract$REQUEST 的信息。该项目仅在公司服务器上运行以供内部使用,但是我不想仅仅因为它永远不会受到攻击而故意编写代码。 +1 供您参考。 即使在受信任的环境中,您也永远不知道客户在尝试解决他们遇到的问题时会遇到什么问题,然后才回复您。【参考方案5】:

我认为,根据您当前的 sn-p 代码,您需要将代码顺序设置如下

if(isset($_REQUEST))

   $_SESSION['submitted_filter_values'] = $_REQUEST;


if(isset($_SESSION['submitted_filter_values']))

   extract($_SESSION['submitted_filter_values']);
   unset($_SESSION['submitted_filter_values']);

【讨论】:

感谢您的回复,感谢您的宝贵时间。

以上是关于在同一页面上提交表单时如何预填充下拉列表?的主要内容,如果未能解决你的问题,请参考以下文章

dreamweaver中如何把表单数据提交显示在当前页面上?

禁用提交 btn 时,预填充的表单输入元素不接受第一个输入

如何验证表单数据,然后通过 AJAX 发送,然后在同一页面上显示提交的结果

如何使用 jQuery 重新填充表单提交时隐藏的 CSV 字段

PHP 表单 - 提交时停留在同一页面上

当同一页面上有多个使用同一个类时,如何验证电子邮件提交表单?