Chciałbym dzisiaj omówić problem renderowania danych pobranych poprzez AJAX’owe zapytanie poprzez jQuery w ASP .NET(chociaż metoda tak na prawdę jest uniwersalna dla PHP, JSP itd.).
Można wszystko wyrenderować „na piechotę”- czyli iterując przez otrzymany wynik w postaci XML lub JSON, sklejać to do string’a a następnie przypisać do pożądanego kontenera i wyświetlić. Takie rozwiązanie oczywiście spełni swoją rolę ale ma kilka poważnych wad:
- jest sprzeczne z oddzieleniem logiki naszej aplikacji z warstwą prezentacji- powoduje to zamieszanie w kodzie i frustrację
- wyobraźcie sobie, że grafik daje wam nowy template strony- będziecie mieli przed sobą duuuużo żmudnej i nudnej pracy
Co zrobić w takim przypadku? Ano zastosować silnik do renderowania danych po stronie klienta. Moim ulubionym jest jTemplates i to na nim będzie się opierać mój przykład. Dobra koniec wstępu bierzmy się do pracy:).
Cały projekt jest dostępny do pobrania na końcu wpisu więc nie będę opisywał po kolei jak tworzyć projekt itd. bo moim zdaniem mija się to z celem i wydłuża niepotrzebnie ten wpis.
W naszej solucji mamy następujące pliki:
W folderze js mamy bibliotekę jQuery w wersji 1.3.2, jTemplates to wspomniany wyżej silnik renderowania po stronie klienta w wersji 0.7.8 i livequery- plugin który wykrywa zmiany w DOM naszego dokumentu html i jeżeli jest taka potrzeba przypisuje zdarzenia do nowych obiektów które pojawiły się na stronie (troszkę niefortunnie to wytłumaczyłem ale będzie przykład).
FooWrapper i Game właściwie tylko „opakowują” nasze obiekty i tyle powinniśmy o nich wiedzieć- kilka properties- nic ciekawego:).
Ok mamy za sobą opis projektu więc skupmy się na ciekawych rzeczach. Zawartość pliku Default.aspx:
W sekcji body:
<form id="form1" runat="server">
<div>
<asp:Button ID="btnAjaxCall" runat="server" Text="Click me!" />
<div id="container"></div>
</div>
</form>
Po krótce przycisk pod którego podpięte jest zdarzenie i kontener w którym będzie wyświetlana treść.
Sekcja head jest ciekawsza:
$(document).ready(function() {
$("#<%= btnAjaxCall.ClientID %>").click(function(e) {
$.ajax({
type: "POST",
cache: true,
async: false,
url: "WebMethods.aspx/GetProduct",
data: "{}",
contentType: "application/json; charset=utf-8",
dataType: "json",
beforeSend: function() {
},
success: function(msg) {
$('#container').setTemplate($("#TemplateResultsTable").html());
$('#container').processTemplate(msg);
},
error: function(msg) {
}
});
$("span.spanClass").click(function() {
var bar = $(this).attr("title");
alert(bar);
});
e.preventDefault();
});
});
Najbardziej tutaj interesuje nas oczywiście zdarzenie podpięte pod przycisk „btnAjaxCall”. Jest to standardowe AJAX’owe zapytanie do statycznej metody osadzonej w stronie WebMethods.aspx o nazwie GetProduct. Jej kod wygląda następująco:
[WebMethod]
public static FooWrapper[] GetProduct()
{
List<FooWrapper> foos = new List<FooWrapper>();
FooWrapper foo1 = new FooWrapper();
foo1.Name = "John Doe";
foo1.Bar = "Nothing";
foo1.IsOld = false;
List<Game> mariuszGames = new List<Game>();
Game game1= new Game();
game1.Title = "UnrealTournament 2004";
Game game2 = new Game();
game2.Title = "Quake 3";
mariuszGames.Add(game1);
mariuszGames.Add(game2);
foo1.Games = mariuszGames.ToArray();
FooWrapper foo2 = new FooWrapper();
foo2.Name = "Stefan Schmidt";
foo2.Bar = "Nix";
foo2.IsOld = true;
List<Game> stefanGames = new List<Game>();
Game game3 = new Game();
game3.Title = "DragonBall";
Game game4 = new Game();
game4.Title = "StreetFighter";
stefanGames.Add(game3);
stefanGames.Add(game4);
foo2.Games = stefanGames.ToArray();
foos.Add(foo1);
foos.Add(foo2);
return foos.ToArray();
}
Czyli ogólnie mówiąc zwraca przykładowe dane w postaci tablicy obiektów FooWrapper która przez jQuery automatycznie zostanie serializowana do postaci JSON. Tak wynik zapytania wygląda w firebug’u:

Teraz jedyne co nam pozostaje to wyrenderować dane. Tak jak pisałem na początku do tego celu użyjemy pluginu jTemplates. Jego wywołanie wygląda następująco (w metodzie success zapytania AJAX):
$('#container').setTemplate($("#TemplateResultsTable").html());
$('#container').processTemplate(msg);
Obiekt „TemplateResultsTable” jest naszym templatem który jest zdefiniowany także w sekcji head strony i wygląda następująco:
<script type="text/html" id="TemplateResultsTable">
{#template MAIN}
{#foreach $T.d as FooWrapper}
{#include ROW root=$T.FooWrapper}
{#/for}
</table>
{#/template MAIN}
{#template ROW}
<span title="{$T.Bar}" {#if $T.IsOld == true} style=" color: Red;" {#else} style=" color: Blue;" {#/if}>{$T.Name}</span>
<p>Games owned</p>
<ul>
{#foreach $T.Games as Object}
<li>{$T.Object.Title}</li>
{#/for}
</ul>
<br />
{#/template ROW}
</script>
Ciekawą rzeczą tutaj jest składnia przypominająca Pythona (która nawiasem mówiąc jest niezwykle wygodna) i zagnieżdżona pętla foreach iterująca po obiektach Games. Warto tutaj zauważyć, że obiekt Games w odpowiedzi JSON nie posiada typu więc należy odnosić się do niego jako Object.
A oto wynik naszej aplikacji:
Na początku tylko button:

Po naciśnięciu wyrenderowane dane:

A tyle trwała cała operacja:

Na koniec małe podsumowanie. W tym przykładzie chciałem wam przedstawić jak łatwo stworzyć szybkie, niezawodne i eleganckie rozwiązanie służące do renderowania po stronie danych, pochodzących z zapytania AJAX, w formacie JSON.
Link do projektu: jTemplates example in ASP .NET
PS jak tylko znajdę dobry plugin do WordPress’a do kolorowania składni nie omieszkam poprawić tego postu.