"use strict"; // Tämä on controlled lomake. Käytä tätä tapaa jos suinkin mahdollista // vrt. kontrolloimaton versio: http://appro.mit.jyu.fi/tiea2120/ohjaus/ohjaus6/2017/react2.html class Lomake extends React.Component { constructor(props) { super(props); // Lomakkeen sisältö muodostuu näiden pohjalta eli näiden on oltava tilassa this.state = { nimi : "", email : "", pvm : "", pvm2 : "", radio : "radio1", checkbox : ["checkbox1"], select : "3", // tarvitaan lomakkeen tyhjäykseen key: Date.now() } this.handleChange = this.handleChange.bind(this); this.handleInsert =this.handleInsert.bind(this); this.checkboxes = []; // checkboxien virheilmoitusten nollaamista varten tarvitaan taulukko } handleChange(event) { // dynaamisuuden takia pitää kikkailla erillisen objektin kautta: let obj = event.target; let arvo = obj.value; let kentta = obj.name; let type = obj.type; let checked = obj.checked; let validity = obj.validity; let newstate = {}; // asetetaan virhe jos ei ole validi. Tässä voisi tehdä myös monimutkaisempia tarkistuksia // pelkkä !valid ei kelpaa, koska jos on asettanut oman virheilmoituksen, niin valid ei ole tosi. kts. ValidityState.customError // if ( !validity.valid ) { if ( validity.badInput || validity.patternMismatch || validity.rangeOverflow || validity.rangeUnderflow || validity.tooLong || validity.tooShort || validity.typeMismatch || validity.valueMissing ) { obj.setCustomValidity("Kentän arvo on virheellinen"); // ähäkutti, eipäs nollatakkaan kontrolloidussa lomakkeessa. Jos halutaan pitää kenttä // kontrolloituna // niin siihen syötetyn arvon on vastattava tilaa koko ajan, koska muuten // renderointi palauttaa kentän tyhjäksi aina virheellisen syötteen yhteydessä // newstate[kentta] = ""; // this.setState(newstate); newstate[kentta] = arvo; this.setState(newstate); // nyt täytyy submitin käsittelyssä vielä erikseen tarkistaa, että kaikki on ok... // jos on käytetty oikein html5-tarkistuksia niin hoituu itsestään return; } else { obj.setCustomValidity(""); } // console.log(event.target); // console.log(kentta, arvo, type, checked); // checkboxit pitää käsitellä erikseen, koska arvoja voi olla monta if ( type == "checkbox" ) { newstate[kentta] = this.state[kentta].slice(0); // tehdään kopio, koska alkuperäistä ei voi suoraan käyttää. Huom. tämä slice-temppu ei riitä, jos taulukossa on objekteja. Ei siis tee "deep" kloonia if ( checked) { // lisätään newstate[kentta].push(arvo); } else { // poistetaan newstate[kentta].splice(newstate[kentta].indexOf(arvo),1); } // tarkistetaan vielä, että varmasti ainakin yksi checkbox oli valittuna. Jos ei niin asetetaan virhe // miten hoidetaan virheilmoitusten nollaus kaikista checkboxeista? // virheilmoitus asettuu nyt siihen, joka on viimeksi tyhjätty, mutta jos // valitaan joku muista niin miten päästään edelliseen käsiksi? if ( newstate[kentta].length == 0 ) { obj.setCustomValidity("Valitse vähintään yksi"); // ratkaisu useamman checkboxin virheilmoituksen nollaamiseen on tallentaa aina talteen ne checkboxit // joille on asetettu virheilmoitus. Sama voitaisiin hoitaa refseillä, mutta // tämä versio on yksinkertaisempi this.checkboxes.push( obj ); } else { obj.setCustomValidity(""); // tässä pitää tyhjentää virheilmoitus _kaikista_ checkboxeista // valituksi tullut checkbox ei välttämättä ole seuraavassa joukossa for( let checkbox of this.checkboxes) { checkbox.setCustomValidity(""); } // palautetaan taulukko tyhjäksi this.checkboxes = []; } } // kaikki muut kuin checkboxit menevät helposti else { newstate[kentta] = arvo; } this.setState(newstate); } handleInsert(event) { event.preventDefault(); let kentat = ["nimi","email","pvm","pvm2","radio","checkbox","select"]; let virhe = 0; for ( let i of kentat ) { if ( this.state[i] == "" || this.state[i].length == 0 ) { // tänne ei pitäisi päästä... console.log(i, "virhe"); virhe++; } } if ( !virhe ) { // nollataan lomake nollaamalla tila alkuperäiseksi // ei tarvita refsia! let newstate = { nimi : "", email : "", pvm : "", pvm2 : "", radio : "radio1", checkbox : ["checkbox1"], select : "3", // muutetaan fieldsetin keyn arvoa jolloin se renderoituu uudelleen // ilman tätä saadaan tyhjistä kentistä heti punaiset reunukset key: Date.now() } this.setState(newstate); // tämä tarvitaan myös, että virheilmoitustilanne nollautuu event.target.reset(); console.log("kaikki ok!"); } } // select-kentän oletusvalinta alustetaan value-attribuutilla reactissa // value-kenttään ei saa oletuksena sijoittaa mitään tai kenttään ei voi sijoittaa mitään. // jos lomakkeen haluaa helposti nollata niin on annettava oletusarvot value-attribuutilla ja // näiden arvojen pitää olla tilamuuttujissa, koska muuten kenttiä ei voi muokata. Lomakkeesta // tulee kontrolloitu. // Huomaa, että tilan ON vastattava tilannetta, joka näkyy lomakkeelle eli esim. käyttäjällä // on kesken sähköpostiosoitteen syöttäminen -> kenttä on vielä epävalidi -> tilassa on oltava // keskeneräinen syöte, jotta se myös päivittyy sivulle // buttonin tyypin on oltava submit ja lomakkeen tapahtumankäsittelijän on oltava onSubmit niin hoitaa html5-tarkistukset // onclick-käsittelijä buttonissa ei toimi yhtä hyvin. // Huomaa miten jokaisen kentän value tai checked-tila on riippuvainen tämän luokan tilasta render(){ return (
nimi: {this.state.nimi}
email: {this.state.email}
pvm: {this.state.pvm}
pvm2: {this.state.pvm2}
radio: {this.state.radio}
checkbox: { this.state.checkbox.map((element,index, checkbox) => { if (index != checkbox.length-1) return element + ","; else return element;}) }
select: {this.state.select}