A cikksorozat előző részeiben ([1], [2]) az egyszeri adatkötéssel ismerkedtünk, ami sok esetben nagyon hasznos, de mégis az az igazi, ami a megváltozott adatot automatikusan képes frissíteni a felhasználói felületen. Ehhez arra van szükségünk, hogy észrevegyük, ha egy objektum valamelyik tulajdonsága megváltozik, ami lássuk be, JavaScriptben nem is olyan egyszerű feladat.
JavaScriptben ugyanis nincsenek property-k, legalábbis nem a .NET-es értelemben, azaz nincs lehetőségünk getter és setter metódusok írására. Ugyan van egy javasolt elnevezési konvenció – amit egyébként a Microsoft AJAX Library osztályai követnek is – miszerint írjunk get_ és set_ kezdetű metódusneveket, de ez nagyon körülményes megoldás lenne olyan esetekben, amikor primitív adatstruktúrákkal dolgozunk. Képzeljünk el egy webszolgáltatástól JSONban visszakapott Person objektumokból álló tömböt, hol van abban get_ és set_ metódus? Sehol.
Hasonló problémákra az elterjedt megoldás az observer tervezési minta használata: adott egy publisher, akinek a birtokában van az adat és ő szól az érdeklődő subscribereknek, ha az adat megváltozott. Egy JSONos objektum tömb valóban tartalmazza az adatot, csak éppen nem képes szólni, ha az megváltozik. Természetesen nincs akadálya, hogy felruházzuk a tömbünket ilyen funkciókkal, de ha ezt minden esetben nekünk kell megírnunk, akkor az egyrészt nagyon sok munka (JavaScriptben a sima “sok”=”brutál sok”), másrészt nagyon idegesítő lesz a sokféle implementációval vacakolni.
Itt jön a képbe a Sys.Observer osztály, ami képes egy tetszőleges objektumot igazi publisherré tenni.
Vegyük a korábban már látott országokat egy tömbben:
var countries = [
{ Name: 'Austria', Capital: 'Vienna' },
{ Name: 'Australia', Capital: 'Canberra' },
// És így tovább...
];
És jelenítsük meg a már jól ismert DataView vezérlővel deklaratív módon:
<ul
class="sys-template"
sys:attach="dv"
dv:data="{{ countries }}">
<li>
{{ Name }} ({{ Capital }})
</li>
</ul>
Készítsünk két linket, amivel a forrás adatokat manipuláló függvényeket fogjuk hívni:
<a href="#" onclick="onAdd()">Hozzáad</a>
<a href="#" onclick="onDelete()">Töröl</a>
Ezek után, ha az onAdd és onDelete függvényekben megpróbáljuk közvetlenül módosítani a countries változót, akkor hiába várjuk, hogy a módosítások megjelenjenek a felületen. Nosza vessük be a Sys.Observer osztályt és tegyük a countries gyűjteményt observable-lé:
Sys.Observer.makeObservable(countries);
Majd figyeljük meg például a Visual Studio Watch ablakában, hogy hogyan változott a saját kis primitív adatstruktúránk:
A gyűjteményünk kapott néhány metódust és ha ezeket használjuk az adatok módosítására, akkor arról minden subscriber értesülni fog. A metódusok nevei eléggé magukért beszélnek, egyedül annyit emelnék ki, hogy ha nem akarjuk az értesítést azonnal elküldeni – például mert több tulajdonságot módosítunk sorban – akkor a módosítások előtt hívjuk meg a beginUpdate, a végén pedig az endUpdate metódust. Az előbbi felfüggeszti az értesítés küldést, az utóbbi pedig elküldi őket. A makeObservable metódust egyszerűbb esetekben akár el is hagyhatjuk, ekkor azonban a Sys.Observer osztály “statikus” metódusainak első paraméteréül át kell adnunk, hogy melyik objektummal dolgozzanak.
Visszatérve a fenti példára, írjuk meg az onAdd és onDelete metódusokat az új metódusok segítségével:
function onAdd()
{
countries.add({ Name: 'France', Capital: 'Paris' });
}
function onDelete()
{
countries.removeAt(9);
}
Ezzel készen is vagyunk, ha kipróbáljuk látni fogjuk, hogy a gyűjtemény módosításai azonnal látszódnak a felhasználói felületen, nem kell külön frissítenünk. Már csak azzal vagyok adós, hogy miért? A megoldás pedig igen egyszerű: a DataView okos osztály, észreveszi, hogy observable adatforrással dolgozik és automatikusan feliratkozik a változásaira, nekünk ezzel nem kell foglalkoznunk.
Érdemes kipróbálni, hogy mi történik, ha nem a gyűjteményen, hanem a gyűjtemény egyik elemén módosítunk, például így:
countries[7].Name = 'Magyarország';
Megmondom már most: semmi, a DataView rá se bagózik. De hogy mindennek mi köze a live bindinghoz, azt azonban csak legközelebb árulom el...
A cikkhez tartozó forráskód letölthető innen.