首页 文章

你如何克服html表单嵌套限制?

提问于
浏览
195

我知道xhtml不支持嵌套的表单标签,我已经阅读了其他答案
这里有关于这个主题的stackoverflow,但我仍然没有想出一个优雅的问题解决方案 .

有人说你不需要它,他们想不到这种情况需要这样做 . 好吧,我个人无法想到一个我不需要它的场景 .

让我们看一个非常简单的例子:

您正在创建一个博客应用程序,并且您有一个表单,其中包含一些字段,用于创建新帖子和工具栏,其中包含“保存”,“删除”,“取消”等“操作” .

<form   
 action="/post/dispatch/too_bad_the_action_url_is_in_the_form_tag_even_though_conceptually_every_submit_button_inside_it_may_need_to_post_to_a_diffent_distinct_url"  
method="post">  

    <input type="text" name="foo" /> <!-- several of those here -->  
    <div id="toolbar">
        <input type="submit" name="save" value="Save" />
        <input type="submit" name="delete" value="Delete" />
        <a href="/home/index">Cancel</a>
    </div>
</form>

我们的目标是以不需要javascript的方式编写表单,只需要简单的旧HTML表单和提交按钮 .

由于动作URL是在Form标签中定义的,而不是在每个单独的提交按钮中定义,我们唯一的选择是发布到通用URL,然后启动“if ... then ... else”来确定按钮的名称提交 . 不是很优雅,但我们唯一的选择,因为我们不想依赖javascript .

唯一的问题是,按“删除”,将提交服务器上的所有表单字段,即使此操作所需的唯一内容是带有post-id的隐藏输入 . 在这个小例子中没什么大不了的,但是我的LOB应用程序中有数百个(可以这么说)字段和标签的表单(由于要求)必须一次性提交所有内容,无论如何这看起来效率很低而浪费 . 如果支持表单嵌套,我至少能够在其自己的表单中包含“删除”提交按钮,只包含post-id字段 .

您可以说“只需实施”删除“作为链接而不是提交” . 这在许多层面都是错误的,但最重要的是因为像这里的“删除”这样的副作用动作永远不应该是GET请求 .

所以我的问题(特别是那些说他们不需要形成嵌套的人)是你做什么的?是否有任何优雅的解决方案,我缺少或底线真的“要么需要javascript或提交一切”?

16 回答

  • -1

    我将完全按照您的描述实现这一点:将所有内容提交到服务器并执行一个简单的if / else来检查单击了哪个按钮 .

    然后我将实现一个Javascript调用绑定到表单的onsubmit事件,该事件将在表单提交之前进行检查,并且只将相关数据提交给服务器(可能通过页面上的第二个表单以及处理该事物所需的ID隐藏的输入,或者使用您需要作为GET请求传递的数据刷新页面位置,或者向服务器发送Ajax帖子,或者......) .

    这样没有Javascript的人就可以正常使用表单,但是服务器负载是偏移的,因为拥有Javascript的人只提交所需的单个数据 . 让自己专注于只支持一个或另一个真正限制你的选择不必要 .

    或者,如果您在公司防火墙后面工作,并且每个人都禁用了Javascript,您可能需要执行两个表单并使用一些CSS魔术使其看起来像删除按钮是第一个表单的一部分 .

  • 2

    我想出了一个用jquery做的好方法 .

    <form name="mainform">    
        <div id="placeholder">
        <div>
    </form>
    
    <form id="nested_form" style="position:absolute">
    </form>
    
    <script>
       $(document).ready(function(){
          pos = $('#placeholder').position();
          $('#nested_form')
             .css('left', pos.left.toFixed(0)+'px')
             .css('top', pos.top.toFixed(0)+'px');
       });
    </script>
    
  • 11

    你可以在页面上并排显示表单,但不能嵌套 . 然后使用CSS使所有按钮排列漂亮?

    <form method="post" action="delete_processing_page">
       <input type="hidden" name="id" value="foo" />
       <input type="submit" value="delete" class="css_makes_me_pretty" />
    </form>
    
    <form method="post" action="add_edit_processing_page">
       <input type="text" name="foo1"  />
       <input type="text" name="foo2"  />
       <input type="text" name="foo3"  />
       ...
       <input type="submit" value="post/edit" class="css_makes_me_pretty" />
    </form>
    
  • 16

    如果你真的不想使用多个表单(如Jason sugests),那么使用按钮和onclick处理程序 .

    <form id='form' name='form' action='path/to/add/edit/blog' method='post'>
        <textarea name='message' id='message'>Blog message here</textarea>
        <input type='submit' id='save' value='Save'>
    </form>
    <button id='delete'>Delete</button>
    <button id='cancel'>Cancel</button>
    

    然后在javascript(我在这里使用jQuery为了简单)(尽管添加一些onclick处理程序是相当过分的)

    $('#delete').click( function() {
       document.location = 'path/to/delete/post/id'; 
    });
    $('#cancel').click( function() {
       document.location = '/home/index';
    });
    

    我也知道,如果没有javascript,这将使一半的页面无效 .

  • 13

    好吧,如果您提交表单,浏览器也会发送输入提交名称和值 . 所以你能做的是

    <form   
     action="/post/dispatch/too_bad_the_action_url_is_in_the_form_tag_even_though_conceptually_every_submit_button_inside_it_may_need_to_post_to_a_diffent_distinct_url"  
    method="post">  
    
        <input type="text" name="foo" /> <!-- several of those here -->  
        <div id="toolbar">
            <input type="submit" name="action:save" value="Save" />
            <input type="submit" name="action:delete" value="Delete" />
            <input type="submit" name="action:cancel" value="Cancel" />
        </div>
    </form>
    

    所以在服务器端你只需要查找启动宽度字符串“action:”的参数,其余部分告诉你要采取什么操作

    因此,当您单击按钮时,保存浏览器会向您发送类似foo = asd和action:save = Save的内容

  • 174

    或者你可以动态分配表格actiob ...可能不是最好的解决方案,但肯定会减轻服务器端的逻辑......

    <form name="frm" method="post">  
        <input type="submit" value="One" onclick="javascript:this.form.action='1.htm'" />  
        <input type="submit" value="Two" onclick="javascript:this.form.action='2.htm'" />  
    </form>
    
  • 1

    我没有javascript就可以这样做的一种方法是添加一组定义要采取的动作的单选按钮:

    • 更新

    • 删除

    • 无论如何

    然后,动作脚本将根据单选按钮组的值采取不同的操作 .

    另一种方法是按照你的建议在页面上放两个表单,而不是嵌套 . 但是布局可能难以控制:

    <form name="editform" action="the_action_url"  method="post">
       <input type="hidden" name="task" value="update" />
       <input type="text" name="foo" />
       <input type="submit" name="save" value="Save" />
    </form>
    
    <form name="delform" action="the_action_url"  method="post">
       <input type="hidden" name="task" value="delete" />
       <input type="hidden" name="post_id" value="5" />
       <input type="submit" name="delete" value="Delete" />
    </form>
    

    使用处理脚本中隐藏的“任务”字段进行适当的分支 .

  • 4

    我的解决方案是让按钮调用JS函数,然后在主窗体中写入然后提交表单

    <head>
    <script>
    function removeMe(A, B){
            document.write('<form name="removeForm" method="POST" action="Delete.php">');
            document.write('<input type="hidden" name="customerID" value="' + A + '">');
            document.write('<input type="hidden" name="productID" value="' + B + '">');
            document.write('</form>');
            document.removeForm.submit();
    }
    function insertMe(A, B){
            document.write('<form name="insertForm" method="POST" action="Insert.php">');
            document.write('<input type="hidden" name="customerID" value="' + A + '">');
            document.write('<input type="hidden" name="productID" value="' + B + '">');
            document.write('</form>');
            document.insertForm.submit();
    }
    </script>
    </head>
    
    <body>
    <form method="POST" action="main_form_purpose_page.php">
    
    <input type="button" name="remove" Value="Remove" onclick="removeMe('$customerID','$productID')">
    <input type="button" name="insert" Value="Insert" onclick="insertMe('$customerID','$productID')">
    
    <input type="submit" name="submit" value="Submit">
    </form>
    </body>
    
  • -1

    我通过包含一个复选框来解决这个问题,具体取决于该人想要做什么形式 . 然后使用1按钮提交整个形成 .

  • 0

    HTML5具有“表单所有者”的概念 - 输入元素的“表单”属性 . 它允许模拟嵌套表单并解决问题 .

  • -1

    在回答Yar在他自己的回答评论中发布的问题时,我提出了一些JavaScript,它将调整iframe的大小 . 对于表单按钮的情况,可以安全地假设iframe将位于同一个域中 . 这是我使用的代码 . 您将不得不改变自己网站的数学/常量:

    function resizeIFrame(frame)
    {
        try {
            innerDoc = ('contentDocument' in frame) ? frame.contentDocument : frame.contentWindow.document;
            if('style' in frame) {
                frame.style.width = Math.min(755, Math.ceil(innerDoc.body.scrollWidth)) + 'px';
                frame.style.height = Math.ceil(innerDoc.body.scrollHeight) + 'px';
            } else {
                frame.width = Math.ceil(innerDoc.body.scrollWidth);
                frame.height = Math.ceil(innerDoc.body.scrollHeight);
            }
        } catch(err) {
            window.status = err.message;
        }
    }
    

    然后这样称呼它:

    <iframe ... frameborder="0" onload="if(window.parent && window.parent.resizeIFrame){window.parent.resizeIFrame(this);}"></iframe>
    
  • 52

    我认为杰森是对的 . 如果您的“删除”操作是最小的操作,请将其单独放在一个表单中,并将其与其他按钮对齐,以使界面看起来像一个统一的表单,即使它不是 .

    或者,当然,重新设计你的界面,让人们完全删除其他地方,不要求他们看到巨大的形式 .

  • 0

    一些古老的话题,但这个可能对某人有用:

    正如上面提到的那样 - 你可以使用虚拟表格 . 我不得不在不久前克服这个问题 . 起初我完全忘记了这个HTML限制,只是添加了嵌套表单 . 结果很有趣 - 我从嵌套中丢失了我的第一个表单 . 然后事实证明,在实际的嵌套表单之前简单地添加一个虚拟表单(将从浏览器中删除)是一种“技巧” .

    就我而言,它看起来像这样:

    <form id="Main">
      <form></form> <!--this is the dummy one-->
      <input...><form id="Nested 1> ... </form>
      <input...><form id="Nested 1> ... </form>
      <input...><form id="Nested 1> ... </form>
      <input...><form id="Nested 1> ... </form>
      ......
    </form>
    

    适用于Chrome,FireFox和Safari . IE最多9(不确定大约10)并且Opera不检测主窗体中的参数 . 无论输入如何,$ _REQUEST全局都是空的 . 内心形式似乎无处不在 .

    尚未测试此处描述的其他建议 - 围绕嵌套表单的字段集 .

    EDIT :框架集没有't work! I simply added Main form after the others (no more nested forms) and used jQuery' s "clone"在按钮单击时复制表单中的输入 . 为每个克隆的输入添加.hide()以保持布局不变,现在它就像魅力一样 .

  • -2

    使用 iframe 作为嵌套表单 . 如果他们需要共享字段,那么...它不是真正嵌套的 .

  • -1

    我知道这是一个老问题,但HTML5提供了几个新选项 .

    第一种是将表单与标记中的工具栏分开,为删除操作添加另一个表单,并使用 form 属性将工具栏中的按钮与其各自的表单相关联 .

    <form id="saveForm" action="/post/dispatch/save" method="post">
        <input type="text" name="foo" /> <!-- several of those here -->  
    </form>
    <form id="deleteForm" action="/post/dispatch/delete" method="post">
        <input type="hidden" value="some_id" />
    </form>
    <div id="toolbar">
        <input type="submit" name="save" value="Save" form="saveForm" />
        <input type="submit" name="delete" value="Delete" form="deleteForm" />
        <a href="/home/index">Cancel</a>
    </div>
    

    此选项非常灵活,但原始帖子还提到可能需要使用单个表单执行不同的操作 . HTML5再次受到拯救 . 您可以在提交按钮上使用 formaction 属性,因此同一表单中的不同按钮可以提交到不同的URL . 这个例子只是在表单外部的工具栏中添加了一个克隆方法,但它在表单中的嵌套方式相同 .

    <div id="toolbar">
        <input type="submit" name="clone" value="Clone" form="saveForm"
               formaction="/post/dispatch/clone" />
    </div>
    

    http://www.whatwg.org/specs/web-apps/current-work/#attributes-for-form-submission

    这些新功能的优点是它们在没有JavaScript的情况下以声明方式完成所有这些操作 . 缺点是旧浏览器不支持它们,因此您必须为旧版浏览器进行一些填充 .

  • 1

    这个讨论仍然是我感兴趣的 . 在原始帖子的后面是OP似乎共享的“要求” - 即具有向后兼容性的形式 . 作为撰写本文时工作的人有时必须支持IE6(以及未来几年),我会深入研究 .

    在没有推动框架的情况下(所有组织都希望在兼容性/健壮性方面保证自己,并且我没有将此讨论作为框架的理由),Drupal对此问题的解决方案很有意思 . Drupal也是直接相关的,因为该框架有一个长期的政策“它应该在没有Javascript的情况下工作(只有你想要)”,即OP的问题 .

    Drupal使用它相当广泛的form.inc函数来查找triggering_element(是的,这是代码中的名称) . 请参阅API页面上列出的代码底部form_builder(如果您想深入了解详细信息,建议使用source - drupal-x.xx / includes / form.inc) . 构建器使用自动HTML属性生成,通过它,可以返回检测按下了哪个按钮,并相应地执行(这些也可以设置为运行单独的进程) .

    除了表单构建器之外,Drupal将数据'delete'操作拆分为单独的URL /表单,可能出于原始帖子中提到的原因 . 这需要某种搜索/列表步骤(呻吟另一种形式!,但用户友好)作为初步 . 但这有消除"submit everything"问题的优势 . 带有数据的大表单用于's intended purpose, data creation/updating (or even a ' merge'action) .

    换句话说,解决问题的一种方法是将表单转换为两个,然后问题就消失了(HTML方法也可以通过POST来纠正) .

相关问题