Sei que o XHTML não suporta tags de formulário aninhadas e já li outras respostas aqui no Stack Overflow sobre esse assunto, mas ainda não descobri uma solução elegante para o problema.
Alguns dizem que você não precisa e que eles não conseguem pensar em um cenário onde isso seria necessário. Bem, pessoalmente, não consigo pensar em um cenário que não precisei.
Vamos ver um exemplo muito simples:
Você está criando um aplicativo de blog e possui um formulário com alguns campos para criar uma nova postagem e uma barra de ferramentas com "ações" como "Salvar", "Excluir", "Cancelar".
<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>
Nosso objetivo é escrever o formulário de uma maneira que não exija JavaScript , basta usar o formulário HTML antigo e enviar botões.
Como o URL da ação é definido na tag Form e não em cada botão de envio individual, nossa única opção é postar em um URL genérico e iniciar "if ... then ... else" para determinar o nome do botão que foi submetido. Não é muito elegante, mas é a nossa única opção, pois não queremos confiar no JavaScript.
O único problema é que pressionar "Excluir" enviará TODOS os campos do formulário no servidor, mesmo que a única coisa necessária para essa ação seja uma entrada Oculta com o ID da postagem. Não é grande coisa neste pequeno exemplo, mas tenho formulários com centenas (por assim dizer) de campos e guias em meus aplicativos LOB que (por causa dos requisitos) precisam enviar tudo de uma só vez e, de qualquer forma, isso parece muito ineficiente e um desperdício. Se o aninhamento de formulários fosse suportado, eu seria capaz de quebrar o botão de envio "Excluir" dentro de seu próprio formulário, apenas com o campo pós-identificação.
Você pode dizer "Basta implementar o" Excluir "como um link em vez de enviar". Isso seria errado em muitos níveis, mas o mais importante é que ações de efeito colateral como "Excluir" aqui nunca devem ser uma solicitação GET.
Portanto, minha pergunta (principalmente para aqueles que dizem que não precisavam de aninhamento de formulários) é O que você faz? Existe alguma solução elegante que estou faltando ou o resultado final é realmente "Exija JavaScript ou envie tudo"?
Respostas:
Eu implementaria isso exatamente como você descreveu: envie tudo para o servidor e faça um simples if / else para verificar em qual botão foi clicado.
E, em seguida, implementaria uma chamada Javascript vinculando o evento onsubmit do formulário, que seria verificado antes do envio do formulário e apenas enviaria os dados relevantes ao servidor (possivelmente por meio de um segundo formulário na página com o ID necessário para processar a coisa como uma entrada oculta, ou atualize o local da página com os dados que você precisa passar como uma solicitação GET ou faça uma postagem do Ajax no servidor ou ...).
Dessa forma, as pessoas sem Javascript podem usar o formulário corretamente, mas a carga do servidor é compensada porque as pessoas que possuem Javascript estão enviando apenas os dados necessários. Ficar focado em apenas apoiar um ou outro realmente limita suas opções desnecessariamente.
Como alternativa, se você trabalha com um firewall corporativo ou algo assim e todo mundo tem o Javascript desabilitado, convém fazer dois formulários e trabalhar um pouco de CSS para parecer que o botão excluir faz parte do primeiro formulário.
fonte
Sei que essa é uma pergunta antiga, mas o HTML5 oferece algumas novas opções.
A primeira é separar o formulário da barra de ferramentas na marcação, adicionar outro formulário para a ação de exclusão e associar os botões na barra de ferramentas aos respectivos formulários usando o
form
atributoEssa opção é bastante flexível, mas a postagem original também mencionou que pode ser necessário executar ações diferentes com um único formulário. O HTML5 vem em socorro, novamente. Você pode usar o
formaction
atributo nos botões de envio, para que botões diferentes no mesmo formulário possam ser enviados para URLs diferentes. Este exemplo apenas adiciona um método clone à barra de ferramentas fora do formulário, mas funcionaria da mesma forma aninhada no formulário.http://www.whatwg.org/specs/web-apps/current-work/#attributes-for-form-submission
A vantagem desses novos recursos é que eles fazem tudo isso declarativamente sem JavaScript. A desvantagem é que eles não são suportados em navegadores mais antigos; portanto, você precisará fazer um polyfilling para navegadores mais antigos.
fonte
form=
serve o suporte do navegador - o CanIUse não diz realmente. caniuse.com/#feat=forms<input>
para declarar botões. o<button>
elemento foi introduzido há 15 anos para esse fim. Realmente pessoas.<input>
ou<button>
elementos é irrelevante, embora os botões sejam geralmente mais apropriados para as barras de ferramentas, como você diz. A propósito, os elementos do botão não são suportados por todos os navegadores há 15 anos.você pode ter os formulários lado a lado na página, mas não aninhados. então use CSS para deixar todos os botões alinhados?
fonte
O HTML5 tem uma ideia do "proprietário do formulário" - o atributo "formulário" para os elementos de entrada. Permite emular formulários aninhados e resolverá o problema.
fonte
Tipo de tópico antigo, mas este pode ser útil para alguém:
Como alguém mencionado acima - você pode usar a forma fictícia. Eu tive que superar esse problema há algum tempo. No começo, esqueci completamente essa restrição de HTML e apenas adicionei os formulários aninhados. O resultado foi interessante - perdi minha primeira forma do aninhado. Acabou sendo uma espécie de "truque" para simplesmente adicionar um formulário fictício (que será removido do navegador) antes dos formulários aninhados reais.
No meu caso, fica assim:
Funciona bem com Chrome, FireFox e Safari. IE até 9 (não tenho certeza sobre 10) e o Opera não detecta parâmetros na forma principal. O global $ _REQUEST está vazio, independentemente das entradas. Formas internas parecem funcionar bem em todos os lugares.
Não testei outra sugestão descrita aqui - fieldset em torno de formulários aninhados.
EDIT : Frameset não funcionou! Simplesmente adicionei o formulário Principal após os outros (não há mais formulários aninhados) e usei o "clone" do jQuery para duplicar as entradas no formulário, clicando no botão. Adicionado .hide () a cada uma das entradas clonadas para manter o layout inalterado e agora funciona como um encanto.
fonte
Eu acho que Jason está certo. Se a sua ação "Excluir" é mínima, faça com que ela esteja em um formulário por si só e alinhe-a com os outros botões para fazer com que a interface pareça um formulário unificado, mesmo que não esteja.
Ou, é claro, redesenhe sua interface e permita que as pessoas excluam completamente outro lugar que não exija que elas vejam a forma enormo.
fonte
Uma maneira de fazer isso sem javascript seria adicionar um conjunto de botões de opção que definam a ação a ser tomada:
Em seguida, o script de ação executará ações diferentes, dependendo do valor do conjunto de botões de opção.
Outra maneira seria colocar dois formulários na página, como você sugeriu, mas não aninhados. O layout pode ser difícil de controlar:
Usando o campo "tarefa" oculto no script de manipulação para ramificar adequadamente.
fonte
Essa discussão ainda é do meu interesse. Por trás da postagem original, existem "requisitos" que o OP parece compartilhar - ou seja, um formulário com compatibilidade com versões anteriores. Como alguém cujo trabalho no momento da redação deve às vezes apoiar o IE6 (e nos próximos anos), eu entendo isso.
Sem pressionar a estrutura (todas as organizações vão querer se assegurar da compatibilidade / robustez, e eu não estou usando essa discussão como justificativa para a estrutura), as soluções Drupal para esse problema são interessantes. O Drupal também é diretamente relevante porque a estrutura possui uma política de muito tempo de "deve funcionar sem Javascript (somente se você quiser)", isto é, o problema do OP.
Drupal usa suas funções form.inc bastante extensas para encontrar o elemento triggering (sim, esse é o nome no código). Consulte a parte inferior do código listado na página da API para form_builder (se você quiser pesquisar detalhes, a fonte é recomendada - drupal-x.xx / includes / form.inc ). O construtor usa a geração automática de atributos HTML e, com isso, pode voltar a detectar qual botão foi pressionado e agir de acordo (eles também podem ser configurados para executar processos separados).
Além do construtor de formulários, o Drupal divide as ações de exclusão de dados em URLs / formulários separados, provavelmente pelos motivos mencionados na postagem original. Isso precisa de algum tipo de etapa de pesquisa / listagem ( gere outro formulário !, mas é fácil de usar) como preliminar. Mas isso tem a vantagem de eliminar o problema "enviar tudo". A grande forma com os dados é usada para a finalidade pretendida, criação / atualização de dados (ou até mesmo uma ação de 'mesclagem').
Em outras palavras, uma maneira de contornar o problema é devolver o formulário em dois, depois o problema desaparece (e os métodos HTML também podem ser corrigidos por meio de um POST).
fonte
Use um
iframe
para o formulário aninhado. Se eles precisam compartilhar campos, então ... não está realmente aninhado.fonte
Minha solução é fazer com que os botões chamem funções JS que escrevem e depois enviam formulários fora do formulário principal
fonte
Se você realmente não deseja usar vários formulários (como Jason sugere), use botões e manipuladores ao clicar.
E então em javascript (eu uso o jQuery aqui para facilitar) (mesmo que seja um exagero adicionar alguns manipuladores onclick)
Também sei que isso fará com que metade da página não funcione sem javascript.
fonte
Em resposta a uma pergunta postada por Yar em um comentário à sua própria resposta, apresento algum JavaScript que redimensionará um iframe. No caso de um botão de formulário, é seguro assumir que o iframe estará no mesmo domínio. Este é o código que eu uso. Você precisará alterar as constantes matemáticas / do seu site:
Então chame assim:
fonte
Eu apenas vim com uma boa maneira de fazer isso com o jquery.
fonte
Bem, se você enviar um formulário, o navegador também enviará um nome e um valor de envio de entrada. Então, o que você pode fazer é
no lado do servidor, basta procurar o parâmetro que inicia a string de largura "action:" e a parte restante informa qual ação executar
então, quando você clica no botão Salvar navegador, envia algo como foo = asd & action: save = Save
fonte
Eu contornei o problema incluindo uma caixa de seleção, dependendo da forma que a pessoa queria fazer. Em seguida, use o botão 1 para enviar o formulário inteiro.
fonte
Como alternativa, você pode atribuir o formulário actiob em tempo real ... pode não ser a melhor solução, mas com certeza alivia a lógica do servidor ...
fonte