Lomakkeellani on pudotuslistoja tähän tyyliin:
<select name="Minuutit"> <option value="#">Minuutit</option> <option value="00">00</option> <option value="15">15</option> </select>
Jos lomaketta täyttänyt on jättänyt pakollisia kenttiä täyttämättä ja yrittää lähettää lomakkeen tiedot, ladataan sivu uudestaan ja hänelle annetaan herja. Tässä tilanteessa lomakkeen tekstikentissä, checkboxeissa ja radiobuttoneissa säilyy vallan mainiosti se arvo, joka niissä oli lähetystä yritettäessä, mutta näiden pudotuslistojen sisältö "nollautuu" oletusarvolle.
Miten saisin pudotuslistoihin valitut arvot säilymään virheilmoituksen tapauksessa siten, että käyttäjän ei tarvitse valita niitä uudestaan korjattuaan virheen, josta herja johtui?
Javascriptilla.
<form action="..." onsubmit="return TarkistaLomake(this)"> ... <select id="minuutit" name="minuutit"> ... </select> ... </form>
function TarkistaLomake(form) { if(form.getElementById("minuutit").selects.options[form.getElementById("minuutit").selects.selectedIndex].value == "#") { return false; } return true; }
Ei tää jostakin syystä toimi..?
Eki++: Lomakkeella ei ole metodia getElementById, eikä haetulla elementilläkään olisi ominaisuutta selects.
Viestin otsikosta saa käsityksen, että tarkistus on toteutettu palvelinpäässä PHP:llä ja palvelin virheen sattuessa palauttaa virheilmoituksen lisäksi esitäytetyn lomakkeen. Pudotusvalikosta voi valitun kohdan asettaa selected-attribuutilla, joka skriptin tulee asettaa valittuna olleeseen vaihtoehtoon.
<select name="Minuutit"> <option value="#">Minuutit</option> <option value="00" selected>00</option> <option value="15">15</option> </select>
Hupsista... Näin siinä käy kun ei kokeile vaan kirjoittaa suoraan. Hyvä kun korjasit :)
No itse kysymykseen, omasta mielestäni ei pitäisi tehdä ainoastaan palvelinpään tarkistuksia, vaan pitää se ikään kuin backuppina. JS:llä tarkistukset ensisijaisesti.
Edit: No nyt mä en osaa kirjottaa edes normitekstiä oikein...
Eki++ kirjoitti:
No itse kysymykseen, omasta mielestäni ei pitäisi tehdä ainoastaan palvelinpään tarkistuksia, vaan pitää se ikään kuin backuppina. JS:llä tarkistukset ensisijaisesti.
Täydellisen väärin. Ainoastaan palvelimen päässä tehdyillä validoinneilla on mitään väliä. Selaimessa tehtävät tarkistukset ovat vain käyttömukavuutta lisäävä tekijä, jos niitä käytetään oikein. (Muutoin ne vain aiheuttavat vitutusta.)
Kaikki syöte, mitä käyttäjältä luetaan, täytyy tarkistaa. Selaimessa olevat tarkitukset voi ohittaa, eikä hyökkääjän tarvitse edes käyttää nettiselainta vaan mikä tahansa alkeellinen skripti riittää. Siitä syystä palvelinsovelluksen täytyy varmistaa, että tiedot ovat oikein ja että käyttöoikeudet ovat kohdillaan.
Monesti näkee käytettävän reaaliaikaisia validointeja, jotka tarkistavat yksittäisen kentän pahimmillaan kesken syöttämisen ja alkavat valittaa epäkelvosta arvosta, koska käyttäjä on kerinnyt kirjoittaa sen vasta puoliksi. Tai kun rekisteröityessä kahden salasanakentän arvot tarkistetaan jo ensimmäisen kentän syöttämisen jälkeen -> takuuvarma virhe.
Eki++ kirjoitti:
JS:llä tarkistukset ensisijaisesti.
Tarkastukset tulee joka tapauksessa olla myös palvelinpäässä, sillä selaimessa olevat käyttäjä voi ohittaa joko tarkoituksella tai tietämättään skriptien ollessa poissa käytöstä. Tarkastukset, joilla ei ole merkitystä tietoturvaan, voidaan tosin poikkeustapauksissa suorittaa pelkästään selaimessa.
Selaimessa suoritettavan tarkastuksen tarkoitus on parantaa käytettävyyttä huomauttamalla virheistä ennen lomakkeen lähettämistä. Jos virheellisestä lomakkeesta näytetään alert-ikkuna käyttäjän painettua lähetysnappia, käytännössä mitään hyötyä ei saavuteta perinteiseen palvelinpään takastukseen verrattuna. Esimerkkisi tavoin toimiva tarkastus, joka ei edes huomauta virheistä vaan antaa kuvan rikkinäisestä sivusta, on vielä huonompi.
JS-purkka on toivottavasti historiaa. Nykyaikaista on lisätä required-määre ja laittaa ylimmän valinnan arvo tyhjäksi.
<select required="required"> <option value="">Valitse jotain</option> <option value="00">00</option> </select>
Firefoxissa valinnalle voi hauskasti lisätä attribuutit disabled ja selected, jolloin se on aluksi valittuna mutta siihen ei voi enää palata. En katsonut, mitä speksit sanovat tästä viritelmästä...
Jos tyhjäkin arvo on sallituissa vaihtoehdoissa, voi ylimmälle laittaa jonkin muun arvon ja required-attribuutin sijaan käyttää sitten pattern-attribuuttia sen hylkäämiseen.
Metabolixin vinkkikään ei käsittääkseni ratkaise varsinaista ongelmaani.. vai enkö vain ymmärrä (mikä on täysin mahdollista)?
Lisäys:
Radio-buttonien kohdalla toimii tällainen parivaljakko:
<?php $luonne4val = (isset($_POST['TilaisuudenLuonne']) && $_POST['TilaisuudenLuonne'] == 'Muu') ? 'checked' : ''; ?> <input type="radio" id="til4" name="TilaisuudenLuonne" value="Muu" <?=$luonne4val?>>Muu (tarkenna lisätiedoissa)
Mod. lisäsi kooditagit!
Unohdin sanoa, että tietysti merkkaat required-attribuutilla myös kaikki muut tarvittavat kentät lomakkeelta, jotta lomaketta ei koskaan lähetetä puutteellisena. Palvelinpuolen tarkistusten jälkeen sitten et tulosta mitään puolitäyttä lomaketta sivulle vaan tulostat vain virheilmoituksen, ja takaisin lomakkeeseen pääsee tarvittaessa normaaliin tapaan selaimen historian kautta.
Jos todella haluat tehdä sen ruman purkkaviritelmän, että virhesivulla tulostuu koko lomake uudestaan – mikä on mielestäni selaimen historian kannalta epäkäytännöllistä ja muutenkin rumaa –, joudut tarkistamaan tuolla samalla tavalla jokaisen optionin kohdalla, pitäisikö se valita.
<?php $minuutti = @$_POST["minuutti"]; ?> <option value="00" <?= $minuutti === "00" ? "selected" : "" ?>>00</option> <option value="15" <?= $minuutti === "15" ? "selected" : "" ?>>15</option>
Koodin pituutta voi tietenkin optimoida mm. tekemällä funktion option-elementin tulostukseen.
En minä kyllä tuollakaan saa sitä toimimaan. Ehkä mun pitää luovuttaa oman yrittämisen osalta ja palkata joku joka osaa...
Metabolix kirjoitti:
JS-purkka on toivottavasti historiaa. Nykyaikaista on lisätä required-määre ja laittaa ylimmän valinnan arvo tyhjäksi.
Nykyaikaista on kyllä mielestäni asettaa required ja muut validointisäännöt itse modeliin, josta tiedot asettuvat luotavaan lomakkeeseen automaattisesti (ja validoidaan joko sekä client että server -puolella, tai serverin päässä). Ei purkkailla erillisvalidointeja client puolelle, jotka sitten täytyisi erillisenä toteuttaa serverillä. Muutama suppea esimerkki:
Ruby on rails
# Jos halutaan myös client side -validation, # ladataan tarvittava gem mukaan (gem 'client_side_validations') # Model class Person < ActiveRecord::Base validates :name, presence: true validates_numericality_of :age, less_than_or_equal_to: 100, greater_than_or_equal_to: 0 end # Controllerissa... def create person = Person.create(params[:person]) if person.valid? person.save redirect_to :controller => 'index' end end
<!-- View ---> <%= form_for @person,:url => {:action => "create"}, :validate => true do |f| %> <table> <tr> <td> <%= f.label t :name %> </td> <td> <%= f.text_field :name%> </td> </tr> <tr> <td> <%= f.label t :age %> </td> <td> <%= f.text_field :age%> </td> </tr> <tr> <td> <%= f.submit "Create", :class => "button" %> </td> </tr> </table> <% end %>
C# MVC
//Jos halutaan client side validation ottaa mukaan, //Asetetaan application starttiin //HtmlHelper.ClientValidationEnabled = true; //HtmlHelper.UnobtrusiveJavaScriptEnabled = true; //Model public class Person { [Required] [DisplayName("Name")] public string name { get; set; } [Range(0, 100)] [DisplayName("Age")] public int? age { get; set; } } //controllerissa... [HttpPost] public ActionResult Create(Person person) { if (ModelState.IsValid) { db.Person.Add(person); db.SaveChanges(); return RedirectToAction("Index"); } return View(person); }
<!-- View ---> @using (Html.BeginForm("Create", "Persons")) { <table> <tr> <td> @Html.LabelFor(model => model.name) </td> <td> @Html.EditorFor(model => model.name) @Html.ValidationMessageFor(model => model.name) </td> </tr> <tr> <td> @Html.LabelFor(model => model.age) </td> <td> @Html.EditorFor(model => model.age) @Html.ValidationMessageFor(model => model.age) </td> </tr> <tr> <td> <input type="submit" value="Create" class="button" /> </td> </tr> </table> }
Mitä taas tulee custom validointeihin (esim yksi checkbox ryhmästä tulee olla valittu), tämä toteutettaisiin samalla tavalla, validointiattribuuteilla modeliin.
Sitten vielä PerfectHypertextPreprocessor:illa:
<?php namespace Application\Entity; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity */ class Person { /** * @ORM\Column(type="string", length=128) */ protected $name; public function getName() { return $this->name; } public function setName($name) { $this->name = $name; } }
<?php namespace Application\Form\Person; use Zend\Form\Form; use Zend\InputFilter\InputFilterProviderInterface; class PersonForm extends Form implements InputFilterProviderInterface { const NAME_MAX_LENGHT = 100; public function __construct($form = null) { $this->add(array( 'name' => 'name', 'options' => array( 'label' => 'Name', ), 'attributes' => array( 'required' => 'required', 'maxlength' => self::NAME_MAX_LENGHT, 'placeholder' => 'Person name', ), )); } public function getInputFilterSpecification() { return array( 'name' => array( 'required' => true, 'validators' => array( array('name' => 'NotEmpty', 'options' => array( 'messages' => array( \Zend\Validator\NotEmpty::IS_EMPTY => 'Syötä nimi',), ), ), array('name' => 'StringLength', 'options' => array( 'max' => self::NAME_MAX_LENGHT, 'messages' => array( \Zend\Validator\StringLength::TOO_LONG => 'Nimi on oltava alle ' . intval(self::NAME_MAX_LENGHT) . ' merkkiä pitkä.',), ), ), ), ), ); } }
<?php $this->form->prepare (); ?> <?= $this->form()->openTag($this->form); ?> <div class="form-group"> <?= $this->formRow($this->form->get('name')); ?> </div> <?= $this->form()->closeTag($this->form); ?>
Mod. korjasi kooditagit, PHP ei ole HTML!
Ongelma on korjattu.
Aihe on jo aika vanha, joten et voi enää vastata siihen.