piątek, 11 maja 2012

jQuery - odc. 3

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: