Internal paths
Out of the box a JWt application is a single page
application: regardless of what the user does, the URL displayed
in the location bar does not change. Single page applications
are typically implemented in JavaScript and use Ajax to pull
data from the server, while multipage applications typically
require full page refreshes.
Single page applications have a number of drawbacks:
- Usability
The usability of your web application may suffer because
users lose the ability to use browser history to navigate
through the application, and bookmarks to bookmark particular
content (or application state). Whether this is an actual
usability problem will depend on the type of application: only
when a user's intuition is deceived in trying to use browser
navigation buttons to navigate through the pages in your
application, you should be concerned.
For example, an interactive web application that mimics a
desktop application with a single window whose content is
manipulated might be conceptually considered a single page for
the user.
On the other hand, applications such as web shops, CMS systems, or
online email readers, all have a need for the user to be able to
bookmark certain content pages.
- Deep linking
-
There is no possibility for deep linking to content within
your application from other websites. This is to some extent
related to the previous point. For example a web shop will
want its products pages to be linked to from product review
websites. But for other applications which have no public
information such as email applications, this might not be a
motivation for internal paths.
- Search engine indexing
-
Content in your web application cannot be indexed properly
by search engines. A related problem, which might be more
serious for certain types of applications, is how search
engines will perceive your web application. Web robots index
the web by retrieving pages and following anchors to other
pages. When your application is presented as only a single
page, only the content on your initial page is accessible to
these search engines.
JWt allows the application to define internal paths and handle
changes of internal paths. Because a JWt application is not
composed of pages, a URL does not define to particular page, but
rather a particular application state. An internal path is a
link to a page in a web application.
The widget gallery makes extensive use of internal paths: the
top-level menu provides the first level, and the menu to the
left a second level.
With the help of HTML5's History API, JWt provides a perfect
illusion of a multipage application, but within a single page!
The recommended method to integrate internal path support in
your application is to use internal path links (defined by
WLink) in anchors or menu items, for people to
navigate to a different 'page' in the application, and respond
to internal path change events, to show the new page in
response. thus instead of directly listening to a click event,
the click results in an internal path change.
The main benefit of this approach is that internal path changes
may also originate from a user navigating using the browser's
back and forward buttons, may follow such a link in a new window
(and thus a new session) or may arrive at the internal path
following a deep link from elsewhere, and this approach
decouples the origin of the event from the handling of the
event.
As a corner stone feature in JWt, internal paths are entirely
supported both in Ajax and plain HTML sessions. For browsers
without support for the HTML5 History API, Ajax session will fall
back to named anchors. This effectively makes internal
paths the perfect tool for search engine accessibility of your
application.
Creating Internal Path Links
For the following widgets you can associate an internal path
with the method setLink()
:
In addition, standard item views such as
WTableView
will render links for
LinkRole
data.
In the example below, the push button is configured to navigate
to the internal path /navigation/anchor
; the next item
in the menu bar. The button behaves as an anchor. This is similar to how a
WMenuWidget or a WTabWidget works.
In this example, the menu reacts
to the internal path event and selects the corresponding menu
item. One can also catch the navigation event directly.
Reacting to internal path changes
Whereas in traditional page-based frameworks, a
controller or request router is a central
component that decides what page content needs to be rendered in
response to a particular request, JWt employs a quite different
model. Instead, you can react to internal path changes, by
listening to the WApplication.internalPathChanged()
signal, as you would react to any other event. At any time,
including when the application is started, the current internal
path is available through WApplication.internalPath()
.
The following example shows the basic mechanism to react to an
internal path event.
final void handlePathChange(WText out) {
WApplication app = WApplication.getInstance();
if (app.getInternalPath().equals("/navigation/shop")) {
out.setText("<p>Currently shopping.</p>");
} else {
if (app.getInternalPath().equals("/navigation/eat")) {
out.setText("<p>Needed some food, eating now!</p>");
} else {
out.setText("<p><i>Idle.</i></p>");
}
}
}
void PathChange() {
WContainerWidget container = new WContainerWidget();
new WAnchor(
new WLink(LinkType.InternalPath, "/navigation/shop"), "Shop", (WContainerWidget) container);
new WText(" ", (WContainerWidget) container);
new WAnchor(
new WLink(LinkType.InternalPath, "/navigation/eat"), "Eat", (WContainerWidget) container);
final WText out = new WText((WContainerWidget) container);
out.setInline(false);
WApplication app = WApplication.getInstance();
app.internalPathChanged()
.addListener(
this,
() -> {
handlePathChange(out);
});
handlePathChange(out);
}
Notice how the same function is used to react to an actual event
but also to the initial state. This will be a common pattern in
widgets that support internal path navigation, as they also need
to initialize to the initial internal path.