2009-02-28 56 views
196

我知道XHTML不支持嵌套的表格標籤,我已經看過其他的答案
在這裏計算器關於這個問題,但我仍然還沒有想出一個優雅的解決問題的辦法。你如何克服html表格嵌套限制?

有人說你不需要它,他們不能想象一個場景是,這將是必要的。那麼,我個人不能想到一個我不需要它的場景。

讓我們看到一個很簡單的例子:

你正在一個博客的應用程序,你必須與創建一個新的職位和一個工具欄與「行動」像「保存」,「刪除」一些領域的一種形式, 「取消」。

<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表單並提交按鈕。

由於操作網址在表單標籤定義,而不是在每個單獨提交按鈕,我們唯一的選擇是張貼到一個通用網址,然後開始「如果......那麼......否則」確定的名稱提交的按鈕。不是很優雅,但我們唯一的選擇,因爲我們不想依靠JavaScript。

唯一的問題是,按「刪除」,將提交即使需要爲此採取行動的唯一的事情就是與後ID隱藏輸入服務器上的所有表單字段。在這個小例子中不是很大,但是我的LOB應用程序中有數百個(可以這麼說)字段和標籤的表單(由於需求)必須一次性提交所有內容,並且無論如何,這看起來效率很低和浪費。如果支持表單嵌套,我至少可以在自己的表單中包含「刪除」提交按鈕,只有後置ID字段。

你可能會說「只要執行‘刪除’爲紐帶,而不是提交」。這在很多層面都是錯誤的,但最重要的是,因爲這裏的「刪除」等副作用操作不應該是GET請求。

所以我的問題(尤其是對那些說他們沒有必要的形式嵌套)是你會怎麼做?有沒有優雅的解決方案,我錯過了或底線是真的「要麼JavaScript或提交一切」?我會做沒有JavaScript的

+16

這很有趣,但XHTML允許根據有趣的註釋進行間接嵌套嵌套http://anderwald.info/internet/nesting-form-tags-in-xhtml/ - (X)HTML不允許像「form> form」這樣的嵌套表單,但允許「form> fieldset> form」,W3驗證器說它是有效的,但瀏覽器有這樣的嵌套錯誤。 – Nishi 2010-05-14 07:09:09

+0

可能的重複[是否有效在另一個html表單中有html表單?](http://stackoverflow.com/questions/555928/is-it-valid-to-have-a-html-form-inside-另外-html-form) – 2015-06-04 23:38:29

回答

51

我會按照您所描述的完全實現這一點:將所有內容提交給服務器,並執行一個簡單的if/else來檢查單擊了哪個按鈕。

然後我會實現一個Javascript調用綁定到表單的onsubmit事件,它將在表單提交之前進行檢查,並且僅將相關數據提交給服務器(可能通過頁面上的第二個表單提供需要的ID將事物作爲隱藏的輸入進行處理,或使用您需要作爲GET請求傳遞的數據來刷新頁面位置,或者對服務器執行Ajax帖子,或...)。

這樣,沒有Javascript的人就可以使用表單,但是服務器負載被抵消了,因爲擁有Javascript的人只會提交所需的單個數據。讓自己專注於只支持其中一個或另一個真的會不必要地限制您的選擇。另外,如果你在公司的防火牆後面工作,並且每個人都禁用Javascript,你可能想要做兩種形式,並且使用一些CSS魔法,使它看起來像刪除按鈕是第一種形式的一部分。

+13

OP原始聲明否javascript – Jason 2009-02-28 06:31:22

+24

這種方法的問題在於它不是RESTful。一個保存和刪除對應的資源不同的操作: 「保存」 - > POST/my_resource(創建新資源) 「保存」 - > PUT/my_resource(修改現有資源) 「刪除」 - > DELETE/my_resource(銷燬資源) 問題來了,問題在於POST預計會創建一個新資源。當然,它絕不應該刪除現有的資源。 – user132447 2012-02-25 14:11:16

2

一個辦法是增加一組定義要採取的行動單選按鈕:

  • 更新
  • 刪除
  • 無論

然後,動作腳本將根據單選按鈕組的值採取不同的操作。

另一種方法是按照您的建議在頁面上放置兩個表單,而不是嵌套。佈局可能難以控制:

 
<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> 

在處理腳本中使用隱藏的「任務」字段進行適當分支。

16

你可以在頁面上並排顯示窗體,但不能嵌套。然後使用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> 
+4

是的,它感覺太方便。另外,在一個非常大的頁面中(設想標籤和子標籤以及在多個作用域級別嵌套提交按鈕)幾乎不可能將元素的屏幕位置與文檔中的位置完全分開。 – gCoder 2009-02-28 06:42:26

+3

好吧,它總是在你想做什麼和你能做什麼之間取得平衡。它看起來像這些選項 - 無論是在服務器上處理的一種形式,還是一種難以維護的多種形式 - 明智地選擇:) – Jason 2009-02-28 06:50:21

+3

是的,不幸的是,在html中所有這些限制,我只會堅持支持和將整個表單發送到服務器,然後使用javascript不顯眼地爲支持它的客戶端攔截表單子表單並僅發送真正需要的內容。這是最好的折衷方案。 – gCoder 2009-02-28 06:58:18

-1

如果你真的不想用多種形式(如賈森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的easyness)(即使它是相當矯枉過正添加一些onclick處理)

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

而且我知道,這會令一半的頁面不沒有JavaScript的工作。

+1

除非我忽略了一些東西,否則這並不比鏈接到刪除操作更好:最終結果將是對刪除操作(壞)的GET請求。事實上,它有點誇張,因爲它需要JavaScript來完成一個普通的舊鏈接標籤可以做的事情。 – 2011-02-25 00:49:46

4

我認爲傑森是正確的。如果您的「刪除」操作是最小化操作,則將其自身放在一個表單中,並將其與其他按鈕對齊,以使界面看起來像一個統一表格,即使它不是。

或者,當然,重新設計您的界面,並讓別人完全刪除其他地方,而不需要他們看到巨大的形式。

13

HTML5有一個「form owner」的概念 - 輸入元素的「form」屬性。它允許模擬嵌套表單並解決問題。

+1

任何有關此價值鏈接的參考? – dakab 2016-03-26 08:07:57

+0

請參閱https://www.w3.org/TR/html5/forms.html#form-owner「默認情況下,與窗體關聯的元素與其最近的祖先窗體元素關聯,但如果它是可重新關聯的,則可以有一個指定的表單屬性來覆蓋這個。「 – Nishi 2016-03-26 23:22:33

-2

或者,您也可以分配形式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

使用的iframe的嵌套形式。如果他們需要共享字段,那麼......它並不是真正的嵌套。

-1

爲了迴應Yar在他自己的回答評論中發佈的問題,我提出了一些將調整iframe大小的JavaScript。對於表單按鈕的情況,假設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> 
172

我知道這是一個老問題,但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。缺點是它們在舊版瀏覽器中不支持,所以你必須爲舊版瀏覽器做一些polyfilling。

-1

我只是想出了一個用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> 
0

那麼,如果您提交表單,瀏覽器還會發送一個輸入提交名稱和值。 那麼什麼喲能做的就是

<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> 

等服務器端,您只要看看啓動寬度字符串「行動:」參數,其餘部分告訴你採取什麼行動

所以當你點擊按鈕保存瀏覽器會將您是foo = ASD &行動:拯救老話題=保存

11

類,但是這一次也許有人有用:

正如有人上面提到的 - 你可以用虛擬形式。 前段時間我不得不克服這個問題。起初我完全忘記了這個HTML限制,只是添加了嵌套表單。結果很有趣 - 我從嵌套中丟失了第一個表單。然後,事實證明,在實際的嵌套表單之前添加一個虛擬表單(將從瀏覽器中刪除)是一種「技巧」。

在我的情況是這樣的:

使用Chrome,Firefox和Safari
<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> 

工作正常。 IE高達9(不知道大概10),Opera沒有檢測到主表單中的參數。無論輸入如何,$ _REQUEST全局都是空的。內在形式似乎在任何地方都能正常工

尚未測試此處描述的另一個建議 - 圍繞嵌套窗體的字段集。

編輯:Frameset沒有工作! 我只是在其他人(不再嵌套表單)之後添加主窗體,並使用jQuery的「克隆」在按鈕單擊窗體上覆制輸入。將.hide()添加到每個克隆的輸入以保持佈局不變,現在它像魅力一樣工作。

1

我的解決辦法是讓按鈕調用哪個寫JS的功能,然後提交表單outwith的主要形式

<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

這個討論仍然是我感興趣的。原始文章背後是OP似乎分享的「要求」 - 即具有向後兼容性的形式。作爲寫作時的工作必須有時支持IE6(以及未來幾年)的人,我會挖掘它。如果不推動框架(所有組織都希望自己保證兼容性/健壯性,而且我沒有將這個討論作爲框架的理由),Drupal解決這個問題的方法很有趣。 Drupal也是直接相關的,因爲框架有一個很長的時間策略「它應該沒有Javascript(只有在你想要的時候)」,即OP的問題。

Drupal使用它相當廣泛form.inc函數查找triggering_element(是的,這是代碼中的名稱)。查看form_builder的API頁面上列出的代碼底部(如果您想深入細節,建議使用源代碼 - drupal-x.xx/includes/form.inc)。構建器使用自動HTML屬性生成,並通過它返回檢測按下哪個按鈕,並據此採取行動(這些可以設置爲運行單獨的進程)。

除了表單構建器之外,Drupal會將數據「刪除」操作拆分爲單獨的URL /表單,這可能是由於原始文章中提到的原因。這需要某種搜索/列表步驟(呻吟另一種形式,但用戶友好)作爲初步。但是這具有消除「提交所有內容」問題的優勢。包含數據的大表單用於預期用途,數據創建/更新(甚至是「合併」操作)。

換句話說,解決問題的一種方法是將表單分解爲兩個,然後問題消失(並且HTML方法也可以通過POST來糾正)。