MODUL 8 - LEKCIJA 1

jQuery Unobtrusive AJAX

Asinkrone forme, AJAX zahtjevi i dinamičko osvježavanje stranica u sistemima javne uprave

⏱️ Trajanje: ~3 časa 📚 Nivo: Srednji 🎯 Praktični primjeri: 5

📖 Uvod: Zašto AJAX u javnoj upravi?

AJAX (Asynchronous JavaScript and XML) je tehnika koja omogućava web aplikacijama da asinkrono komuniciraju sa serverom. U kontekstu javne uprave (npr. registar zaposlenih, e-Građanin portali), AJAX je ključan za kreiranje brzih i responzivnih korisničkih interfejsa.

Umjesto da se cijela stranica ponovo učitava prilikom svake akcije (npr. promjena statusa dokumenta, validacija JMBG-a, pretraga predmeta), AJAX omogućava osvježavanje samo specifičnog dijela ekrana. Ovo drastično smanjuje opterećenje servera i štedi bandwidth, što je kritično za sisteme sa hiljadama istovremenih korisnika.

Klijent (Browser) HTML/CSS Interfejs Server (ASP.NET) Controller / Baza Klasični HTTP Zahtjev (Puna stranica) AJAX Zahtjev (Samo podaci)

🔄 ASP.NET Unobtrusive AJAX

ASP.NET MVC donosi koncept Unobtrusive AJAX-a (Nenametljivi AJAX). Umjesto pisanja kompleksnog JavaScript koda unutar HTML elemenata, MVC koristi HTML5 data-* atribute kako bi označio elemente koji zahtijevaju AJAX ponašanje. jQuery skripta čita te atribute i automatski presreće submit forme.

Da bi ovo radilo, potrebno je uključiti paket Microsoft.jQuery.Unobtrusive.Ajax u vaš projekat.

Primjer iz prakse: Pretraga organa uprave

Ukoliko imamo ogromnu listu svih javnih ustanova i ministarstava, pretraga sa osvježavanjem cijele stranice je spora. Koristit ćemo Ajax.BeginForm za brzu i efikasnu pretragu.

🛠️ Unobtrusive AJAX Forma (View)
@* Ne zaboravite uključiti skriptu: <script src="~/Scripts/jquery.unobtrusive-ajax.min.js"></script> *@

@using (Ajax.BeginForm("Search", "Ministry", 
    new AjaxOptions 
    { 
        UpdateTargetId = "ministryResults", // ID elementa gdje se ubacuje PartialView 
        HttpMethod = "GET", 
        InsertionMode = InsertionMode.Replace, // Mijenja sadržaj meta elementa
        LoadingElementId = "loadingIndicator", // Pokazuje spinner dok se učitava
        OnFailure = "showErrorMsg" // Poziva JS funkciju u slučaju greške
    }))
{
    <div class="input-group">
        @Html.TextBox("query", null, new { @class = "form-control", placeholder = "Unesite naziv institucije..." })
        <span class="input-group-btn">
            <button type="submit" class="btn btn-primary">Pretraži</button>
        </span>
    </div>
}

<!-- Indikator učitavanja -->
<div id="loadingIndicator" style="display:none;" class="text-info">
    <i class="fa fa-spinner fa-spin"></i> Pretraživanje baze podataka...
</div>

<!-- Ovdje će se učitati rezultati -->
<div id="ministryResults" class="mt-3">
    @* Sadržaj će biti zamijenjen sa PartialView-om kojeg vraća kontroler *@
</div>

Kontroler koji obrađuje ovaj zahtjev treba vratiti PartialView (djelimični HTML), a ne cijeli View:

🛠️ Kontroler (C#)
public class MinistryController : Controller
{
    private ApplicationDbContext db = new ApplicationDbContext();

    [HttpGet]
    public ActionResult Search(string query)
    {
        // Simulacija kašnjenja servera radi prikaza Loading indikatora
        System.Threading.Thread.Sleep(500);

        var results = db.Departments
                        .Where(d => string.IsNullOrEmpty(query) || d.DepartmentName.Contains(query))
                        .ToList();

        // Vraća samo HTML strukturu za rezultate, ne i Layout stranicu!
        return PartialView("_MinistrySearchResults", results);
    }
}

📡 Manuelni jQuery AJAX

Ponekad Ajax.BeginForm nije dovoljan, jer trebamo finiju kontrolu nad podacima, asinkrone validacije polja pri gubitku fokusa (blur) ili slanje JSON podataka. Tada koristimo čisti jQuery AJAX.

Primjer: Validacija JMBG-a na klijentu

Kada službenik unosi novog zaposlenog, idealno je da se odmah nakon unosa JMBG-a provjeri da li takva osoba već postoji u sistemu, a ne tek kad se klikne "Spasi".

🛠️ jQuery AJAX Poziv za provjeru JMBG
$(document).ready(function() {
    $('#JMBG').on('blur', function() {
        var unesenJmbg = $(this).val();
        var errorSpan = $('#jmbgError');

        if (unesenJmbg.length === 13) {
            $.ajax({
                url: '@Url.Action("CheckJmbgExists", "Employee")', // Sigurno generisanje URL-a
                type: 'POST',
                dataType: 'json',
                data: { jmbg: unesenJmbg },
                success: function(response) {
                    if (response.exists) {
                        errorSpan.text('Zaposlenik sa ovim JMBG (' + response.name + ') već postoji!');
                        errorSpan.removeClass('text-success').addClass('text-danger');
                        $('#btnSubmit').prop('disabled', true);
                    } else {
                        errorSpan.text('JMBG je slobodan za unos.');
                        errorSpan.removeClass('text-danger').addClass('text-success');
                        $('#btnSubmit').prop('disabled', false);
                    }
                },
                error: function(xhr, status, error) {
                    console.error("Greška pri komunikaciji sa serverom: " + error);
                    errorSpan.text('Nije moguće provjeriti JMBG trenutno.');
                }
            });
        }
    });
});

Kontroler koji odgovara na ovaj POST zahtjev vraća JSON objekat koristeći Json() metodu:

🛠️ Kontroler - Vraćanje JSON-a
[HttpPost]
public JsonResult CheckJmbgExists(string jmbg)
{
    var employee = db.Employees.FirstOrDefault(e => e.JMBG == jmbg);
    
    if (employee != null)
    {
        return Json(new { exists = true, name = employee.FirstName + " " + employee.LastName });
    }
    
    return Json(new { exists = false });
}

✅ Zaključak i najbolje prakse

💡 Preporuke za državne sisteme

  • Optimizirajte pretrage: Koristite AJAX za sve forme pretraživanja registara kako biste smanjili payload prenesen kroz mrežu.
  • Feedback korisniku: Uvijek obezbijedite vizuelni indikator (spinner) tokom AJAX zahtjeva, kako službenik ne bi dvaput kliknuo dugme.
  • Fallback: Iako danas svi browseri podržavaju JavaScript, osigurajte da rutiranje i kontroleri rade i bez AJAX-a (tzv. graceful degradation) ukoliko sigurnosne politike institucije blokiraju skripte.