Klient REST z wykorzystaniem biblioteki Backbone.js - router
Mając możliwość stworzenia modelu i widoku dla danych jest się bardzo blisko skontruowaniu w pełni funkcjonalnej aplikacji. Jedną z rzeczy, której może brakować jest nawigacja. Na szczęście Backbone.js umożliwia bardzo intuicyjne nawigowanie wewnątrz aplikacji, na podstawie identyfikatora fragmentu podawanego w adresie po znaku #, dzięki obiektowi Backbone.Router. W tym artykule postaram się dodać taką funkcjonalność na bazie dotychczas stworzonej aplikacji z poprzedniego artykułu.
Chcąc stworzyć router, wystarczy rozszerzyć obiekt Backbone.Router:
define(function(require) {
var AppRouter = Backbone.Router.extend({
routes: {
"": "handleDefault",
"form": "handleForm",
"list": "handleList"
},
appView: null,
viewName: "list",
initialize: function(options) {
if (typeof options.appView !== "undefined") {
this.appView = options.appView;
}
},
handleDefault: function() {
this.handleView("list");
},
handleForm: function() {
this.handleView("form");
},
handleList: function() {
this.handleView("list");
},
handleView: function(viewName) {
this.viewName = viewName;
if (this.appView !== null) {
this.appView.render();
}
}
});
return AppRouter;
});
Obiekt routes mapuje identyfikatory z adresu URL na wywołania konkretnych funkcji routera (domyślnie handleDefault()). Cała reszta to zaimplementowane metody i obsłużenie wykonania ponownego renderowania widoku, przekazanego jako parametr do konstruktora.
Chcąc wykorzystać router, wystarczy stworzyć jego instancję:
this.router = new AppRouter({
appView: this
});
Ponadto po stworzeniu jego instancji, warto zadbać o to, aby bieżący adres został obsłużony:
Backbone.history.start();
Po czym warto obsłużyć zmianę dodanej własności viewName w widoku aplikacji, aby mieć pewność, że zmiana adresu jest poprawnie obsłużona:
var h1 = document.createElement("h1");
h1.appendChild(document.createTextNode("Widok: " + this.router.viewName));
this.el.appendChild(h1);
Przydatną funkcjonalnością routera jest obsługa parametrów przy definiowaniu obiektu routes. Dzięki temu, możemy sparametryzować nazwę widoku i okroić wielkość definicji routera:
define(function(require) {
var AppRouter = Backbone.Router.extend({
routes: {
"": "handleDefault",
":viewName": "handleView"
},
appView: null,
viewName: "list",
initialize: function(options) {
if (typeof options.appView !== "undefined") {
this.appView = options.appView;
}
},
handleDefault: function() {
this.handleView("list");
},
handleView: function(viewName) {
this.viewName = viewName;
if (this.appView !== null) {
this.appView.render();
}
}
});
return AppRouter;
});
Teraz korzystając z działającego routera możliwa jest modyfikacja renderowania widoku głównego:
if (this.router.viewName === "list") {
this.el.appendChild(usersView.render());
var a = document.createElement("a");
a.appendChild(document.createTextNode("Dodaj"));
a.href = "#form";
this.el.appendChild(a);
}
if (this.router.viewName === "form") {
this.el.appendChild(userFormView.render());
}
Aby po zapisie wrócić do listy, wystarczy zmodyfikować obsługę odpowiedniego zdarzenia:
var context = this;
(...)
userFormView.on("saved", function() {
(...)
context.router.handleDefault();
});
Analogicznie można obsłużyć pokazywanie formularza edycji:
usersView.on("change", function(user) {
(...)
context.router.handleView("form");
});
Tym sposobem możliwe jest zaimplementowanie prostej nawigacji, która nie wymaga przeładowywania strony. Osoby zainteresowane odsyłam do dokumentacji.
Przykładowy projekt: