Wśród wielu zalet i możliwości Dojo Toolkit jedną z ciekawszych są widżety. W pracy programisty, przydaje się szczególnie możliwość pisania własnych, które roszerzają możliwości użycia biblioteki.

W związku z tym, że artykuł jest kontynuacją wcześniejszej publikacji, skupię się na rozszerzaniu dotychczasowej wersji aplikacji. Spróbuję stworzyć nowy widżet, wyświetlający aktualną pogodę dla lokalizacji wskazanej przez użytkownika.

Warto rozpocząć pracę od dodania niezbędnych zależności, które można dodać w pliku bower.json:

{
	(...)
	"dependencies": {
		"dojo/dojo": "1.13.0",
		"dojo/dijit": "1.13.0"
	}
}

Pobranie ich sprowadza się do komendy:

bower install

Dla porządku w kodzie, przyjmijmy, że pliki należące do widżetu będą umieszczone w katalogu js/widgets/weather. Proponuję rozpocząć od napisania kodu HTML szablonu, aby zobaczyć jak docelowo ma on wyglądać. Szablon najlepiej umieścić w katalogu templates jako plik WeatherWidget.html:

<div class="widget weather">
	<h1>Pogoda</h1>
	<input placeholder="Miasto"/>
	<button>Sprawdź prognozę</button>
	<p>Temperatura: 20&deg;C</p>
	<p>Ciśnienie: 1000hPa</p>
	<p>Wilgotność: 10%</p>
</div>

Aby umożliwić użycie widżetu, wystarczy w jego katalogu umieścić prostą deklarację w pliku WeatherWidget.js:

define(["dojo/_base/declare", "dijit/_WidgetBase", "dijit/_TemplatedMixin",
		"dojo/text!./templates/WeatherWidget.html"], function(declare, _WidgetBase, _TemplatedMixin, template) {
	return declare([_WidgetBase, _TemplatedMixin], {
		templateString: template
	});
});

Użycie sprowadza się do stworzenia odpowiedniego obiektu i użycia metody placeAt():

new WeatherWidget().placeAt(dojoRoot);

Kolejnym krokiem powinno być zastąpienie treści wyświetlanych w widżecie na zależne od odpowiednich zmiennych. Aby sparametryzować odpowiednie wartości, wystarczy podać domyślne w deklaracji:

return declare([_WidgetBase, _TemplatedMixin], {
	weather: {
		temperature: "20&deg;C",
		pressure: "1000hPa",
		humidity: "10%"
	},
	templateString: template
});

po czym skorzystać z notacji ${nazwaZmiennej}:

<div class="widget weather">
	<h1>Pogoda</h1>
	<input placeholder="Miasto"/>
	<button>Sprawdź prognozę</button>
	<p>Temperatura: <span>${!weather.temperature}</span></p>
	<p>Ciśnienie: <span>${weather.pressure}</span></p>
	<p>Wilgotność: <span>${weather.humidity}</span></p>
</div>

Warto zwrócić uwagę na notację wyświetlania temperatury ${!weather.temperature}, która pozwala na potraktowanie wartości jako kodu HTML (ze względu na encję &deg;) i wklejenie jej do szablonu dosłownie bez konwersji znaków na encje (co w efekcie wyświetliłoby kod encji, a nie jej znaczenie).

Aby móc zmieniać treść poszczególnych elementów drzewa DOM, warto dodać atrybut data-dojo-attach-point znaczników span, input i button z nazwą, dzięki której będziemy mogli się do nich bezpośrednio odwoływać:

<input placeholder="Miasto" data-dojo-attach-point="searchNode"/>
<button data-dojo-attach-point="buttonNode">Sprawdź prognozę</button>
<p>Temperatura: <span data-dojo-attach-point="temperatureNode">${!weather.temperature}</span></p>
<p>Ciśnienie: <span data-dojo-attach-point="pressureNode">${weather.pressure}</span></p>
<p>Wilgotność: <span data-dojo-attach-point="humidityNode">${weather.humidity}</span></p>

Teraz dzięki metodzie postCreate, wyzwalanej po skonstruowaniu widżetu, wystarczy podłączyć odpowiednie zdarzenie pod przycisk (wymagane są zależności dojo/_base/lang i dojo/on):

postCreate: function() {
	this.inherited(arguments);
	this.own(on(this.buttonNode, "click", lang.hitch(this, this.searchWeather)));
}

co sprowadza się do wywołania metody postCreate odziedziczonej po rodzicu i podpięciu zdarzenia click pod przycisk. Metoda own zajmuje się zarządzaniem zdarzeniami i daje nam pewność, że zostaną one wyrejestrowane wraz z usunięciem obiektu. Dodatkowym wsparciem jest metoda lang.hitch, która pozwala nam na uzyskanie uchwytu do funkcji (this.searchWeather) z zapewnieniem odpowiedniego kontekstu wywołania (this).

Do implementacji metody searchWeather potrzebna będzie zależność dojo/request, która pozwoli na wykonanie odpowiedniego żądania z pomocą mechanizmu AJAX:

searchWeather: function() {
	request("http://api.openweathermap.org/data/2.5/weather?units=metric&appid=5915c5a2795f5bcb8ac72eac102364e8&q=" + this.searchNode.value, {
		handleAs: "json",
		headers: {
			"X-Requested-With": null
		}
	}).then(lang.hitch(this, this.refreshWeather));
}

Po wykonaniu odpowiedniego żądania, wyzwolona zostanie metoda refreshWeather wymagająca dojo/html do manipulowania zawartością widżetu:

refreshWeather: function(openWeatherMapResponse) {
	this.weather.temperature = openWeatherMapResponse.main.temp + "&deg;C";
	this.weather.pressure = openWeatherMapResponse.main.pressure + "hPa";
	this.weather.humidity = openWeatherMapResponse.main.humidity + "%";
	html.set(this.temperatureNode, this.weather.temperature);
	html.set(this.pressureNode, this.weather.pressure);
	html.set(this.humidityNode, this.weather.humidity);
}

Po wykonaniu wszystkich kroków, uruchomienie aplikacji powinno skutkować ukazaniem się naszego widżetu, pozwalającego na wpisanie wybranej lokalizacji i wyszukanie pogody dla niej.

Przykładowy projekt: