W tym odcinku poruszę kilka zagadnień, które były przydatne przy realizacji wyszukiwania filmów na YouTube.
Przy pisaniu większej ilości kodu, dobrze jest go sobie jakoś zorganizować. WinJS oferuje pomocnicze metody m.in do definiowania przestrzeni nazw i klas. Przy tak prostej funkcjonalności pobrania danych AtomPub i ich sparsowania z klas nie miałem potrzeby na razie korzystać, natomiast w odrębnych plikach w osobnych przestrzeniach nazw zawarłem sobie m.in logikę do komunikacji z YouTube. Definiowanie przestrzeni to w sumie nic innego jak stosowanie wzorca module. Przykładowo może to wyglądać następująco:
function searchVideos(queryText) {
}
WinJS.Namespace.define("YouTube", {
searchVideos: searchVideos
});
Asynchroniczność jest domeną programowania w Windows 8. Interfejsy WinRT pod C# są widziane w postaci .NET-owego async, a jak jest w Java Scripcie? Tutaj WinRT przyjmuje postać konstrukcji then/done, co jest znajome dla użytkowników jQuery oraz jest implementacją propozycji Common JS Promises/A. Najbardziej w tym wszystkim podoba mi się możliwość tworzenia łańcuchów z then. Czym się różni then od done? M.in tym, że then zwraca promise, done już undefined. Po done nie można już dalej ciągnąć łańcucha…
Na poniższym screenshocie funkcja searchVideos jest asynchroniczna, wywołuje w sobie asynchroniczną metodę retrieveFeedAsync z klienta syndykacji WinRT. Po jej poprawnym wykonaniu wykonuje się funkcja w then, która przetwarza otrzymany rezultat.
Mała dygresja - klient syndykacji wymaga obiektu Uri, przy przekazaniu samego stringa dostaniemy wyjątek.
Nie będę się rozpisywał na temat przetwarzania elementów syndykacji, odpowiednie przykłady można znaleźć choćby w MSDN. Powstało trochę kodu by wyłuskać odpowiednie potrzebne informacje. W C# stosowałem często znaną z Linq extension metodę FirstOrDefault z podaniem warunku. W gołym JS w standardzie ECMA Script 5 mamy trochę metod pomocniczych do tablic, ale dokładnie czegoś takiego nie odnalazłem. Posiłkowałem się tutaj metodą find z biblioteki Underscore, co zaowocowało przykładowo taką linijką kodu:
var group = _.find(item.elementExtensions, function (node) {
return node.nodeName === "group" && node.nodeNamespace === mediaNamespace;
});
Biblioteka jest prosta w użyciu, działają podpowiedzi IntelliSense, można ją zdecydowanie polecić.
Kolejnym zagadnieniem okazała się obsługa pola tekstowego. Chciałem by podobnie jak w C# wyszukiwanie uruchamiało się przy zmianie tekstu z pewnym opóźnieniem czasowym przy wpisywaniu liter. Input tekstowy ma zdarzenie “change”, ale wyzwalane jest ono dopiero po utracie focusa przez kontrolkę. Nowe przeglądarki (a także engine JS natywnej aplikacji wspólny z IE10) obsługują też zdarzenie “input”, które jest wyzwalane przy każdej zmianie tekstu bez potrzeby opuszczania kontrolki. Dodatkowo dodałem tutaj timer. Całościowo przybrało to taką postać:
var searchInput = document.getElementById("search");
var timer = null;
searchInput.addEventListener("input", function () {
if (timer === null) {
timer = setTimeout(function () {
timer = null;
YouTube.searchVideos(searchInput.value).then(function (data) {
listView.itemDataSource = null;
var list = new WinJS.Binding.List(data);
listView.itemDataSource = list.dataSource;
});
}, 500);
}
});
Przy okazji mała dygresja - do zmiany elementów w kontrolce ListView potrzebny jest pokazany kod. Samo przypisanie nowej listy nie odświeża. Możemy już cieszyć się ekranem przedstawionym poniżej:
Na koniec obsłużmy przycisk ze “strzałką w dół”. W tym miejscu chcemy przekazać dane z zaznaczonych elementów ListView do metody rozpoczynającej pobieranie i powrócić do strony startowej. Możemy zrealizować to w następujący sposób:
document.getElementById("cmdDownload").addEventListener("click", function () {
listView.selection.getItems().done(function (items) {
var dataArray = _.map(items, function (item) { return item.data; });
Download.startDownload(dataArray);
});
WinJS.Navigation.navigate("/pages/start/start.html");
});
Na dziś koniec. Stay tuned…