Ovo je nastavak prvog dijela.

Izmjenili smo HTML od zadnji put. Uklonili smo ‘form’ elemente i sada samo koristimo input elemente i formdata sučelje. Razlog je tome što želimo imati više slobode i kontrole.

See the Pen CV Forma 06 by Damir Sijakovic (@dsijak) on CodePen.


Namespace

Započeti ćemo sa ‘dsijak’ objektom. ‘dsijak’ skraćenica moga imena i prezimena. To radimo zbog toga što većina JS libsa koristi window kao namespace. Pa su sa takvim imenom šanse jako male da će doći do toga da je window variabla već zauzeta. Osim toga sve su funkcije na ovaj način lako dostupne.

if (!window.dsijak)
{
    window.dsijak = {};
    window.dsijak.cv = {};
    window.dsijak.cvEl = null;
}
else
{
    window.dsijak.cv = {};
    window.dsijak.cvEl = null;
}

Koristiti ćemo dva objekta. ‘cv’ za naše funkcije i ‘cvEl’ za html elemente. U ‘cvEl’ ćemo odmah skupiti sve HTML elemente s kojima ćemo raditi.

dsijak.cvEl = {
    ime:                  document.getElementById("ds-input-ime"),
    prezime:              document.getElementById("ds-input-prezime"),
    nazivUlice:           document.getElementById("ds-input-naziv-ulice"),
    kucanskiBroj:         document.getElementById("ds-input-kucanski-broj"),
    mjesto:               document.getElementById("ds-input-mjesto"),
    postanskiBroj:        document.getElementById("ds-input-postanski-broj"),
    mobitel:              document.getElementById("ds-input-broj-mobitela"),
    email:                document.getElementById("ds-input-email"),
    datumRodenja:         document.getElementById("ds-input-datum-rodenja"),
    spolMuski:            document.getElementById("ds-input-spol-muski"),
    spolZenski:           document.getElementById("ds-input-spol-zenski"),
    vozackaDa:            document.getElementById("ds-input-vozacka-da"),
    vozackaNe:            document.getElementById("ds-input-vozacka-ne"),
    pdf:                  document.getElementById("ds-input-zivotopis"),
    pdfHidden:            document.getElementById("ds-input-zivotopis-skriveno"),
    prihvacampravila:     document.getElementById("ds-input-pravila-privatnosti"),
    prihvacampravilaText: document.getElementById("ds-input-pravila-text"),
    
    message:              document.getElementById("ds-message"),
    messageTitle:         document.getElementById("ds-message-title"),
    messageTextBody:      document.getElementById("ds-message-text-body"),
    messageButton:        document.getElementById("ds-message-button"),
}    

MESSAGE – PORUKA

Sljedeće su message funkcije. Treba nam funkcija koja će javiti korisniku da je input forma prazna, da su uneseni krivi podaci ili da se dogodila greška na poslužitelju.

dsijak.cv.errorMessage = function(text) 
{ 
    const main = dsijak.cvEl.message;
    dsijak.cvEl.messageTitle.innerHTML = 'Pogreška!';
    dsijak.cvEl.messageTextBody.innerHTML = text;
    dsijak.cvEl.messageButton.style.display = 'inline-block';
    main.style.display = 'inline-block';
    main.style.background = '#222';
    throw text; 
}

Ovdje vidimo da otvaramo mali prozorčić s porukom i na kraju imamo:

throw text;

‘throw’ će zaustaviti daljnje izvođenje javascripta.

Ostale message funkcije:

  • ‘successMessage’ – ista funkcija samo drugačije boje.
  • ‘showWaitingMessage’ – otvara prozorčić ali bez ‘zatvori’ gumba.
  • ‘closeMessage’ – zatvara već otvoren prozorčić.

VALIDATE FUNKCIJA

Validate funkcija zove ‘checkValidity‘ metodu na našim input elementima.

dsijak.cv.validate = function()
{    
    const el = dsijak.cvEl;
    
    if (!el.ime.checkValidity())
    {
        dsijak.cv.setValidationErrorMessage(el.ime);       
    } 
    
    ...
}

Ukoliko input ima grešku, ‘validate’ zove ‘setValidationErrorMessage’ koji šalje poruku u ‘errorMessage’ funkciju.

dsijak.cv.setValidationErrorMessage = function(elem)
{    
    var message = '';
    
    if (elem.id === 'ds-input-ime')
    {
        if (elem.value === '')
        {
            message = 'Morate unijeti polje "Ime"!';
        }
        else
        {
            message = 'Morate unijeti ispravne podatke u polje "Ime"!';
        }        
    }
    ...
}

GETFORMDATA FUNKCIJA

Posao ‘getFormData’ funkcije je da pokupi sve podatke i napravi prilagodbe potrebne za prijenos podataka na poslužitelj.

dsijak.cv.getFormData = function()
{
    var formData = {};    
    formData.ime = dsijak.cvEl.ime.value;
    formData.prezime = dsijak.cvEl.prezime.value;
    formData.nazivUlice = dsijak.cvEl.nazivUlice.value;
    formData.kucanskiBroj = dsijak.cvEl.kucanskiBroj.value;
    formData.mjesto = dsijak.cvEl.mjesto.value;
    formData.postanskiBroj = dsijak.cvEl.postanskiBroj.value;
    formData.mobitel = dsijak.cvEl.mobitel.value;
    formData.email = dsijak.cvEl.email.value;
    formData.datumRodenja = dsijak.cvEl.datumRodenja.value;
    formData.spol = dsijak.cvEl.spolMuski.checked ? 'M' : 'Ž';
    formData.vozacka = dsijak.cvEl.vozackaDa.checked ? 'Da' : 'Ne';
    formData.pdfFilename = dsijak.cvEl.pdf.value;
    formData.prihvacampravila = dsijak.cvEl.prihvacampravila.checked;

    return formData;
}

FORMDATA

Formdata je javascript sučelje koje može generirati query parametre kao da koristimo klasični form HTML tag. Tako da ćemo napraviti ‘postData’ objekt:

var postData = new FormData();  

Zatim uzimamo HTML element koji ima učitanu PDF datoteku:

var pdfInput = dsijak.cvEl.pdfHidden.files;
for (var i=0; i<pdfInput.length; i++) {
    postData.append('ds_pdf_file[]', pdfInput[i]);
}  

Usput, ova ‘for’ petlja je korisna ukoliko imate više učitanih datoteka.

Dalje uzimamo pripremljene podatke sa ‘getFormData’ funkcijom.

var formValues = dsijak.cv.getFormData();      
postData.append("ds_form_data", JSON.stringify(formValues));

Sada nam samo preostaje poslati podatke na poslužitelj.

POST

Imamo sve podatke i treba ih poslati na server. Za to ćemo koristiti ‘sendData’ wrapper funkciju. U funkciji smo zapakirali javascript ‘fetch’ funkciju.

function dsijak_sendData(url, data, cb)
{        
    var send = async function (url = '', data = {})    
    {    
        const response = await fetch(url, {        
            method: 'POST',
            mode: 'cors',
            cache: 'no-cache',
            credentials: 'same-origin',
            redirect: 'follow',
            referrerPolicy: 'no-referrer',
            body: data
        });
        if (response.status != 200){
            return {error: response.status +', '+ response.statusText};
        }     
        
        return response.json();
    }
    
    send(url, data)
    .then(x => { 
		cb(x);                
    });  
}

‘sendData’ uzima argumente: ‘url’ za url na koji šaljemo POST zahtjev, ‘data’ su podaci koje šaljemo i ‘cb’ je callback funkcija koja će odraditi podatke odgovora zahtjeva.

Zahtjev izgleda ovako:

sendData('/cv.php', {hello:"world"}, function(x)
{
    if (x.success) 
    {
        console.log(x.success);
    }
    if (x.fail) 
    {
        console.log(x.fail);
    }
    if (x.error) 
    {
        console.log(x.error); 
    }
});

Odgovor zahtjeva vraća ‘success’, ‘fail’ i ‘error’ keys. Success je npr. odgovor za “korisnik postoji”, fail za “korisnik ne postoji” dok error vraća HTTP greške (http status code). Naravno, bitno je da u PHP-u imamo odgovor koji vraća JSON sa success/fail:

echo json_encode(['success'=> json_encode(["hello"=>"world"])]);  
die();

ili fail:

echo json_encode(['fail'=>  json_encode(["goodbye"=>"world"])]);  
die();

U browser developer tools-ima pod network-om, možemo pratiti POST zahtjev. Isto možete i sa Wireshark ili tcpdump alatima.

ONSUBMIT FUNKCIJA

Ovo je naša glavna funkcija koja se izvodi klikom na gumb ‘Pošalji’. U funkciju smo privremeno ubacili ‘setTimeout’ funkciju da možemo vidjeti ‘dsijak.cv.responseWaiting’ poruku.

dsijak.cv.onSubmit = function()
{
    var validateState = dsijak.cv.validate();
    
    if (validateState)
    {        
        var postData = new FormData();  
              
        var pdfInput = dsijak.cvEl.pdfHidden.files;
        for(var i=0; i<pdfInput.length; i++) {
            postData.append('ds_pdf_file[]', pdfInput[i]);
        }          
        
        var formValues = dsijak.cv.getFormData();      
        postData.append("ds_form_data", JSON.stringify(formValues));  

        dsijak.cv.sendData('/target.php', postData, function(x)
        { 
            dsijak.cv.responseWaiting();
            
            setTimeout(function () {
                                    
                if (x.success)
                {
                    dsijak.cv.responseFinished();
                }
                
                if (x.error)
                {
                    dsijak.cv.responseError(x.error); 
                }
                
                if (x.fail)
                {   
                    dsijak.cv.responseError(x.fail); 
                } 
            
            }, 3000);             
        });         
    }    
}

target.php

Za testiranje ćemo koristiti ‘target.php’ skriptu. Skriptu postavljamo da vraća kao odgovor JSON file i da prima samo POST zahtjev.

Ako imamo ‘ds_pdf_file’ i ‘ds_form_data’ id-e, skripta će nam preko ‘error_log’ funkcije prikazati sadržaj ‘ds_pdf_file’ i ‘ds_form_data’ podataka forme.

<?php

header('Content-type:application/json;charset=utf-8');

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    echo json_encode(['forbidden'=> "Method Not Allowed"]);  
    http_response_code(405);
    die();
}

if (isset($_FILES['ds_pdf_file']) && isset($_POST['ds_form_data']))
{
    error_log(print_r($_FILES['ds_pdf_file'], true));
    error_log(print_r(json_decode($_POST['ds_form_data']), true));
    echo json_encode(['success'=> json_encode("OK")]);  
    die();
}

echo json_encode(['fail'=> json_encode("Bad post request...")]);  
die();  

Arhiva s projektom

GoogleDrive

Raspakirajte arhivu i u terminalu upišite:

php -S localhost:3000

Na kraju nam ostaje još PHP dio.