W odcinku trzecim trochę moich notatek o obsłudze szablonów w jQuery. Trzeba przyznać, że są dość rozbudowane, a jednocześnie całkiem wysokopoziomowe i intuicyjne. Mimowolnie przy konkretnych sytuacjach mam skojarzenia, jak to jest rozwiązane w Silverlight/WPF. Pozwoliłem sobie trochę na takich porównań.
Plik: jquery.tmpl.min.js
$.tmpl(“<div>${Expression}</div>”, object)
$(“itemTemplate”).tmpl(item)
obiekty json
$.tmpl(“<div class=’product’>${Name}</div>”, product).appendTo(“#container”);
$(“#productTemplate”).tmpl(products).appendTo(“#productList”);
<script id=”productTemplate” type=”text/x-jquery-tmpl”> //ignorowane przez samą przeglądarkę
<tr>
<td>${Name}</td>
<td>${Price}</td>
</tr>
</script>
lub <tr>…</tr> w oddzielnym pliku ProductTemplate.htm
$.get(“ProductTemplate.htm”, function(data) {
$.tmpl(data, products).appendTo(“#productList”);
});
W Silverlight bardzo często przypinanie szablonów DataTemplate odbywa się w deklaratywny sposób lub automatycznie po typie obiektu z danymi (od wersji 5). Tutaj jest popularne podejście imperatywne (możliwe też jak najbardziej w Silverlight, aczkolwiek tam bardzo rzadko zleca się szablonowanie kolekcji w bezpośredni sposób, najczęściej służą do tego kontrolki ItemsControl lub je rozszerzające). Realizacja szablonów w obu przypadkach deklaratywna - w Silverlight XAML i data binding, tutaj HTML i obowiązujące na obszarze szablonów wyrażenia.
Tagi w szablonach
${Expression} - properties, wywołania funkcji JS
function formatDate(inputDate) {
return inputDate.toDateString();
};
<tr>
<td>${Name}</td>
<td>${formatDate(Date)}</td>
<td>
{{if Tags}}
<ul>
{{each Tags}}
<li>${Name}</li>
{{/each}}
</ul>
{{else}}
<span>No tags</span>
{{/if}}
</td>
</tr>
{{each}} {{/each}}
{{if}} {{else}} {{/if}}
W Silverlight formatować dane można poprzez odpowiednią konfigurację data bindingu tj. konwertery zawierające własną implementację lub poprzez StringFormat. Tutaj możemy bezpośrednio wywołać sobie funkcję (z poziomu XAML też można wywołać w sposób deklaratywny funkcję np. na zdarzenie załadowania, ale funkcja nie jest w szablonie, tylko w obiekcie biznesowym). W Silverlight funkcję if else może spełnić behavior zmieniający wizualizację w zależności od zbindowanej do niego wartości. Each nie jest potrzebny, wystarczy użyć jakiejś ItemsControl w szablonie.
Zagnieżdżanie
{{tmpl “template”}} - renderowanie szablonu dla bieżącego data context’u
<script id=”tagsTemplate” type=”text/x-jquery-tmpl”>
<ul>
{{each Tags}}
<li>${Name}</li>
{{/each}}
</ul>
</script>
{{if Tags}}
{{tmpl “#tagsTemplate”}}
{{else}}
<span>No tags</span>
{{/if}}
{{tmpl(data) “template”}} - renderowanie szablonu dla danych przekazanych jako context
<script id=”tagTemplate” type=”text/x-jquery-tmpl”>
<li>${Name}</li>
</script>
{{if Tags}}
<ul>
{{tmpl(Tags) “tagTemplate” }}
</ul>
{{else}}
<span>No tags</span>
{{/if}}
W Silverlight do zagnieżdżenia jednego szablonu w drugim szablonie należy w tym drugim umieścić kontrolkę typu ContentControl / ItemsControl i do niej przypiąć pierwszy szablon.
Kontekst szablonu
$item - renderowany bieżący element szablonu
$item.data - bieżący element z danymi, dla którego jest renderowany szablon
<td>${$item.data.Name}</td> - pełna forma od skrótu ${Name}
$item.parent - rodzic elementu szablonu, przy braku zagnieżdżeń null
$item.parent.data - data context rodzica
<td>${$item.parent.data.Name} contains ${Name}</td>
W Silverlight również możemy przekazywać obiekt szablonu w kodzie, aczkolwiek robi się to rzadziej. Dane dla szablonu to po prostu bardziej uniwersalny DataContext. Do rodzica można odnosić się poprzez binding hierarchiczny (od wersji 5) lub wędrować w drzewie wizualnym.
Encoding
{{html expression}} - nie koduje wyrażenia
<td><a href=”http://…/#!/${$item.data.id}”>${Name}</a></td> - działa
Gdy link <a></a> jest w property Name obiektu:
<td>${$item.data.Name}</td> - encoding, zostanie wyświetlony kod html w postaci źródłowej
<td>{{html Name}}</td> - wyświetlają się linki
W przypadku Silverlight zanim XAML w postaci tekstu zostanie dodany do drzewa wizualnego, powinniśmy go zamienić na postać obiektową wywołując specjalną metodę. W przypadku HTML może dokonać tego sama przeglądarka.
Zagnieżdżanie z wrap
{{wrap “template”}}content{{/wrap}} - renderuje zawartość html opakowaną w szablon
{{wrap(data) “template”}}content{{/wrap}} - przekazuje część danych do szablonu opakowującego
{{wrap “#wrapTemplate”}}
<div>${Name}</div>
{{/wrap}}
<script id=”wrapTemplate” type=”text/x-jquery-tmpl”>
<li>
{{each $item.html(“div”)}}
{{html $value}}
{{/each}}
</li>
</script>
W Silverlight zagnieżdżanie można zrobić przez ContentControl /ItemsControl na szablonie.
Cachowanie szablonów
- kompilacja przy pierwszym użyciu
- możliwość cachowania skompilowanych
- odwoływanie się do skompilowanych po kluczu/nazwie
$.template(“cachedProduct”, $(“#productTemplate”));
$.tmpl(“cachedProduct”, products);
Odwołanie do zcachowanego szablonu w innym szablonie na osobnej stronie HTML:
po prostu - “cachedProduct”
W Silverlight programista może sobie trzymać obiekt szablonu w pamięci jeśli operował na nim w sposób imperatywny, ale najczęściej tym się nie zajmuje. Twórcy Silverlight zawarli pewne optymalizacje w samym frameworku.
Opcje szablonów
Przekazywanie parametrów wejściowych i funkcji
$(“#productTemplate”).tmpl(products,
{
NewDate: new Date(2012, 5, 15)
formatDateFunc: function (inputDate) { return inputDate.toLocaleDateString(); }
}
).appendTo(#productList”);
w szablonie:
{{if $item.NewDate < Date }} …
<td>${$item.formatDateFunc(Date)}</td>
Przekazywać zmiennych i funkcji do samych szablonów w Silverlight nie można, ale poprzez data binding i zachowania można osiągnąć wszystkie potrzebne scenariusze.
Renderowanie
Zmiana szablonu dla zaznaczonego wiersza:
- zcachowane szablony dla poszczególnych stanów wizualnych wiersza
- dostęp do danych podlegających szablonowaniu
- podmiana szablonu
- ponowny rendering in-line
currentProduct = null;
$(#productList).delegate(“.product”, “click”, function() {
//przywracanie poprzednio zaznaczonego
if(currentProduct) {
currentProduct.tmpl = $.template(“cachedProductTemplate”);
currentProduct.update();
}
currentProduct = $.tmplItem($(this));
currentProduct.tmpl = $.template(“cachedSelectedProductTemplate”);
currentProduct.update();
//przeładowanie details dla zaznaczonego wiersza
$(“#currentProductDetails”).empty();
$.tmpl(“cachedDetailsTemplate”, currentProduct.data).appendTo(“#currentProductDetails”);
});
Zmienna $index wewnątrz {{$each }}
Poprzez dynamiczne dodawanie można też wyświetlać szczegóły pod zaznaczonym wierszem.
Przełączanie widoków w Silverlight jest realizowane przez stany wizualne. Kontrolki same nimi zarządzają np. w ListBoxItem jest stan wizualny dla zaznaczonego wiersza, a także wiele innych stanów. Podobnie jest w dużo bardziej złożonym DataGrid, który potrafi wyświetlać panel ze szczegółami pod zaznaczonym wierszem. Bezpośrednie przypisywanie szablonów w sposób imperatywny wykonuje się dużo rzadziej, częściej w kodzie samych kontrolek. Natomiast po przypisaniu szablonu do kontrolki, nie wywołujemy na niej z zewnątrz dodatkowej metody do ponownego renderowania.
Brak komentarzy:
Prześlij komentarz