Wiem, że XHTML nie obsługuje zagnieżdżonych znaczników formularzy i przeczytałem już tutaj inne odpowiedzi na temat przepełnienia stosu dotyczące tego tematu, ale wciąż nie znalazłem eleganckiego rozwiązania tego problemu.
Niektórzy twierdzą, że nie potrzebujesz go i że nie mogą wymyślić scenariusza, gdyby był on potrzebny. Cóż, osobiście nie mogę wymyślić scenariusza, w którym go nie potrzebowałem.
Zobaczmy bardzo prosty przykład:
Tworzysz aplikację blogową i masz formularz z kilkoma polami do tworzenia nowego postu oraz pasek narzędzi z „czynnościami”, takimi jak „Zapisz”, „Usuń”, „Anuluj”.
<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>
Naszym celem jest napisanie formularza w sposób niewymagający JavaScript , tylko zwykły stary formularz HTML i przyciski przesyłania.
Ponieważ adres URL akcji jest zdefiniowany w znaczniku Form, a nie w każdym przycisku wysyłania, naszą jedyną opcją jest opublikowanie pod ogólnym adresem URL, a następnie rozpoczęcie „jeśli ... to ... inaczej”, aby określić nazwę przycisku, który został złożony. Niezbyt elegancki, ale nasz jedyny wybór, ponieważ nie chcemy polegać na JavaScript.
Jedynym problemem jest to, że naciśnięcie „Usuń” spowoduje przesłanie WSZYSTKICH pól formularza na serwerze, mimo że jedyną rzeczą potrzebną do wykonania tej akcji jest Ukryte wejście z identyfikatorem post-id. Niezbyt duża sprawa w tym małym przykładzie, ale mam formularze z setkami (że tak powiem) pól i zakładek w moich aplikacjach LOB , które (z powodu wymagań) muszą przesyłać wszystko za jednym razem, a w każdym razie wydaje się to bardzo nieefektywne i marnotrawstwo. Gdyby obsługiwane było zagnieżdżanie formularzy, mógłbym przynajmniej owinąć przycisk wysyłania „Usuń” wewnątrz własnego formularza tylko polem post-id.
Możesz powiedzieć „Po prostu zaimplementuj„ Usuń ”jako link zamiast przesyłać”. Byłoby to niewłaściwe na tak wielu poziomach, ale co najważniejsze, ponieważ działania niepożądane, takie jak „Usuń” tutaj, nigdy nie powinny być żądaniem GET.
Więc moje pytanie (szczególnie do tych, które mówią, że nie potrzebują zagnieżdżania formularzy) brzmi: co robisz? Czy jest jakieś eleganckie rozwiązanie, którego mi brakuje, a sedno brzmi: „Wymagaj JavaScript lub prześlij wszystko”?
Odpowiedzi:
Zaimplementowałbym to dokładnie tak, jak opisałeś: prześlij wszystko na serwer i zrób prosty jeśli / jeszcze, aby sprawdzić, który przycisk został kliknięty.
A następnie zaimplementowałbym wywołanie JavaScript wiążące w zdarzeniu onsubmit formularza, które sprawdzałoby przed przesłaniem formularza i przesyłało tylko odpowiednie dane do serwera (być może poprzez drugi formularz na stronie z identyfikatorem potrzebnym do przetworzenia rzeczy jako ukryte dane wejściowe lub odśwież lokalizację strony danymi, które musisz przekazać jako żądanie GET, lub opublikuj post Ajax na serwerze lub ...).
W ten sposób osoby bez Javascript mogą dobrze korzystać z formularza, ale obciążenie serwera jest równoważone, ponieważ ludzie, którzy mają Javascript, przesyłają tylko jeden potrzebny element danych. Skoncentrowanie się na wspieraniu tylko jednego z nich naprawdę niepotrzebnie ogranicza twoje opcje.
Alternatywnie, jeśli pracujesz za korporacyjną zaporą sieciową lub coś takiego i wszyscy mają wyłączoną obsługę Javascript, możesz chcieć zrobić dwie formy i popracować nad magią CSS, aby wyglądała, jakby przycisk usuwania był częścią pierwszej formy.
źródło
Wiem, że to stare pytanie, ale HTML5 oferuje kilka nowych opcji.
Pierwszym z nich jest oddzielenie formularza od paska narzędzi w znacznikach, dodanie innego formularza dla akcji usuwania i powiązanie przycisków na pasku narzędzi z odpowiednimi formularzami za pomocą
form
atrybutu.Ta opcja jest dość elastyczna, ale w oryginalnym poście wspomniano również, że może być konieczne wykonywanie różnych działań za pomocą jednego formularza. HTML5 znów na ratunek. Możesz użyć
formaction
atrybutu w przyciskach przesyłania, aby różne przyciski w tej samej formie mogły przesyłać różne adresy URL. Ten przykład po prostu dodaje metodę klonowania do paska narzędzi poza formularzem, ale działałby tak samo zagnieżdżony w formularzu.http://www.whatwg.org/specs/web-apps/current-work/#attributes-for-form-submission
Zaletą tych nowych funkcji jest to, że robią to wszystko deklaratywnie bez JavaScript. Wadą jest to, że nie są one obsługiwane w starszych przeglądarkach, dlatego w starszych przeglądarkach trzeba by było wykonać polifilling.
źródło
form=
miło wiedzieć, do czego służy przeglądarka - CanIUse tak naprawdę nie mówi. caniuse.com/#feat=forms<input>
Deklaracja przycisków jest złą praktyką .<button>
element został wprowadzony 15 lat temu do tego celu. Naprawdę ludzie.<input>
czy<button>
elementów, nie ma znaczenia, chociaż przyciski są zwykle bardziej odpowiednie dla pasków narzędzi, jak mówisz. Nawiasem mówiąc, elementy przycisków nie są obsługiwane przez wszystkie przeglądarki od 15 lat.czy możesz mieć formularze obok siebie na stronie, ale nie zagnieżdżone. następnie użyć CSS, aby wszystkie przyciski były w porządku?
źródło
HTML5 ma pojęcie „właściciel formularza” - atrybut „forma” dla elementów wejściowych. Pozwala emulować zagnieżdżone formularze i rozwiązuje problem.
źródło
Niby stary temat, ale ten może być przydatny dla kogoś:
Jak ktoś wspomniano powyżej - możesz użyć fikcyjnego formularza. Jakiś czas temu musiałem rozwiązać ten problem. Na początku całkowicie zapomniałem o tym ograniczeniu HTML i po prostu dodałem zagnieżdżone formularze. Wynik był interesujący - straciłem pierwszą formę z zagnieżdżonego. Potem okazało się, że to „sztuczka” polegająca na dodaniu fikcyjnego formularza (który zostanie usunięty z przeglądarki) przed faktycznymi zagnieżdżonymi formularzami.
W moim przypadku wygląda to tak:
Działa poprawnie z Chrome, FireFox i Safari. IE do 9 (nie jestem pewien co do 10) i Opera nie wykrywa parametrów w głównej formie. Globalny $ _REQUEST jest pusty, niezależnie od danych wejściowych. Formy wewnętrzne wydają się wszędzie dobrze działać.
Nie przetestowałem innej opisanej tutaj sugestii - zestaw pól wokół zagnieżdżonych form.
EDYCJA : Zestaw ramek nie działał! Po prostu dodałem formularz Główny po pozostałych (nie zagnieżdżonych) i użyłem „klonu” jQuery'ego, aby powielić dane wejściowe w formularzu po kliknięciu przycisku. Dodano .hide () do każdego sklonowanego wejścia, aby zachować niezmieniony układ, a teraz działa jak urok.
źródło
Myślę, że Jason ma rację. Jeśli czynność „Usuń” jest minimalna, ułóż ją w formie samodzielnie i ustaw w linii z innymi przyciskami, aby interfejs wyglądał jak jedna zunifikowana forma, nawet jeśli nie jest.
Lub, oczywiście, przeprojektuj swój interfejs i pozwól ludziom usunąć gdzie indziej całkowicie, co nie wymaga od nich wcale zobaczenia formularza.
źródło
Jednym ze sposobów, w jaki zrobiłbym to bez javascript, byłoby dodanie zestawu przycisków opcji, które określają akcję, którą należy podjąć:
Następnie skrypt akcji podejmowałby różne działania w zależności od wartości zestawu przycisków opcji.
Innym sposobem byłoby umieszczenie dwóch formularzy na stronie, tak jak sugerowałeś, ale nie zagnieżdżonych. Układ może być trudny do kontrolowania:
Użycie ukrytego pola „zadania” w skrypcie obsługi do odpowiedniego rozgałęzienia.
źródło
Ta dyskusja wciąż mnie interesuje. Za oryginalnym postem znajdują się „wymagania”, które wydaje się, że PO dzieli - tj. Formularz z kompatybilnością wsteczną. Jako ktoś, kogo praca w momencie pisania musi czasem obsługiwać z powrotem do IE6 (i przez wiele lat), kopie to.
Bez popychania frameworka (wszystkie organizacje będą chciały się upewnić co do kompatybilności / solidności, a ja nie używam tej dyskusji jako uzasadnienia frameworka), rozwiązania Drupala w tej kwestii są interesujące. Drupal ma również bezpośrednie znaczenie, ponieważ framework ma długą politykę: „powinien działać bez Javascript (tylko jeśli chcesz)”, tj. Problem PO.
Drupal używa dość obszernych funkcji form.inc, aby znaleźć element wyzwalający (tak, taka jest nazwa w kodzie). Zobacz dolną część kodu wymienionego na stronie API dla form_builder (jeśli chcesz zagłębić się w szczegóły, zalecane jest źródło - drupal-x.xx / include / form.inc ). Konstruktor korzysta z automatycznego generowania atrybutów HTML, dzięki czemu może po powrocie wykryć, który przycisk został naciśnięty, i działać odpowiednio (można je skonfigurować tak, aby uruchamiały również osobne procesy).
Oprócz konstruktora formularzy Drupal dzieli akcje „usuń” dane na osobne adresy URL / formularze, prawdopodobnie z powodów wymienionych w oryginalnym poście. Wymaga to pewnego rodzaju kroku wyszukiwania / wpisu ( jęczenie w innej formie !, ale jest przyjazny dla użytkownika) jako wstępne. Ma to jednak tę zaletę, że eliminuje problem „prześlij wszystko”. Duża forma z danymi jest używana zgodnie z przeznaczeniem, tworzeniem / aktualizowaniem danych (lub nawet działaniem „scalania”).
Innymi słowy, jednym ze sposobów obejścia problemu jest przekształcenie formularza na dwa, a następnie problem znika (a metody HTML można również poprawić za pomocą testu POST).
źródło
Użyj
iframe
dla zagnieżdżonego formularza. Jeśli muszą udostępniać pola, to ... to nie jest tak naprawdę zagnieżdżone.źródło
Moim rozwiązaniem jest, aby przyciski wywoływały funkcje JS, które zapisują, a następnie przesyłają formularze poza formularzem głównym
źródło
Jeśli naprawdę nie chcesz używać wielu formularzy (jak sugeruje Jason), użyj przycisków i programów obsługi onclick.
A potem w javascript (używam jQuery tutaj dla łatwości) (nawet jeśli jest to dość przesada w dodawaniu niektórych programów obsługi onclick)
Wiem też, że spowoduje to, że połowa strony nie będzie działać bez javascript.
źródło
W odpowiedzi na pytanie zadane przez Yara w komentarzu do jego własnej odpowiedzi przedstawiam JavaScript, który zmieni rozmiar iframe. W przypadku przycisku formularza można bezpiecznie założyć, że element iframe będzie w tej samej domenie. To jest kod, którego używam. Będziesz musiał zmienić matematykę / stałe swojej witryny:
Nazwij to tak:
źródło
Właśnie wymyśliłem fajny sposób na zrobienie tego z jquery.
źródło
Cóż, jeśli prześlesz formularz, przeglądarka wyśle również wejściową nazwę i wartość przesłania. Więc co możesz zrobić, to
więc po stronie serwera po prostu szukasz parametru, który rozpoczyna szerokość ciągu „akcja:”, a reszta mówi ci, jaką akcję podjąć
więc po kliknięciu przycisku Zapisz przeglądarka wysyła ci coś takiego jak foo = asd & action: save = Save
źródło
Obejrzałem ten problem, dodając pole wyboru w zależności od formy, jaką osoba chciała zrobić. Następnie użyłem 1 przycisku, aby przesłać cały formularz.
źródło
Alternatywnie możesz przypisać formularz actiob w locie ... może nie być najlepszym rozwiązaniem, ale na pewno zwalnia logikę po stronie serwera ...
źródło