webfirmframework for Java Experts
URL rewriting/routing in wffweb-12
The advantage of URL rewriting/routing in this framework is that it changes only the needful part of the UI (so the server sends only the data required for that portion), it will not download/reload the entire page. We can get the same performance advantage of a single page application with url rewriting/routing feature.
URIStateSwitch.whenURI
or
AbstractHtml.whenURI
AbstractHtml
is the implementation class of
URIStateSwitch
interface so
whenURI
methods can be called on any tag (but on
NoTag
only consumer based overloading methods are allowed.).
whenURI
method mainly has four arguments. They are,
whenURI(predicate, successSupplier/successConsumer,
failSupplier/failConsumer, index)
. The argument of
predicate.test
is the changed URI. The argument of consumer is an
TagEvent
object which contains info like the changed URI, the sourceTag etc...
There are many overloading methods available
with different combinations of these arguments for ease of use.
The
whenURI
method can be called multiple times on a tag, the
failSupplier/failConsumer is valid only on the last
whenURI
call.
Now, let's talk about how it works. There are client side and
server side methods to change URI of the app, at server side
browserPage.setURI
can be called and at client side
wffAsync.setURI
can be called, their various usage is explained in the upcoming
section.
The main logic is when there is a URI change the predicate will be
invoked and if the
predicate.test
method returns
true
, the successSupplier/successConsumer will be invoked otherwise
the failSupplier/failConsumer will be invoked unless there is
further predicates to test, i.e. we can call
whenURI
method to add multiple actions. Here, the role of the supplier is
to provide innerHtml/child tags for the corresponding tag that
means the existing children of the tag will be replaced with the
provided tags (returned by the supplier). The role of consumer is
to do any operation at the time of URI change and the current
children of the tag will not be altered unlike supplier.
Checkout this sample code here.
AbstractHtml div = new Div(null);
div.whenURI(uriEvent -> uriEvent.uriAfter().startsWith("/ui/user"),
() -> {return new AbstractHtml[]{ new H1(null).give(TagContent::text, "h1")};});
When
setURI
method is called either from server side or client side, the
predicate will invoke and if the predicate test returns true then
existing children of
div
will be replaced with
H1
otherwise existing children will be removed as there is no
failConsumer/failSupplier passed.
Let's see an example with both successSupplier and failSupplier
AbstractHtml div = new Div(null);
div.whenURI(uriEvent -> uriEvent.uriAfter().startsWith("/ui/user"),
() -> {return new AbstractHtml[]{ new H1(null).give(TagContent::text, "h1")};},
() -> {return new AbstractHtml[]{ new H2(null).give(TagContent::text, "h2")};});
When
setURI
method is called either from server side or client side, the
predicate will invoke and if the predicate test returns true then
existing children of
div
will be replaced with
H1
otherwise with
H2
.
Let's see an example with multiple
whenURI
methods
AbstractHtml div = new Div(null);
div.whenURI(uriEvent -> uriEvent.uriAfter().startsWith("/ui/user"),
() -> {return new AbstractHtml[]{ new H1(null).give(TagContent::text, "h1")};});
div.whenURI(uriEvent -> uriEvent.uriAfter().startsWith("/ui/admin"),
() -> {return new AbstractHtml[]{ new H2(null).give(TagContent::text, "h2")};},
() -> {return new AbstractHtml[]{ new H3(null).give(TagContent::text, "h3")};});
When
setURI
method is called either from server side or client side, the
predicate of the first
whenURI
action will invoke and if the predicate test returns true then the
existing children of
div
will be replaced with
H1
if that predicate test returns false it will invoke the predicate of the second
whenURI
action if the test returns true then existing children of
div
will be replaced with
H2
if test returns false
then existing children of
div
will be replaced with
H3
.
In short:
If
browserPage.setURI("/ui/user")
is called the div
will contain h1
tag.
If
browserPage.setURI("/ui/admin")
is called the div
will contain h2
tag.
If
browserPage.setURI("/ui/other")
is called the div
will contain h3
tag.
In the above example there is no failSupplier in the first
whenURI
method because the failSupplier/failConsumer is valid only on the
last
whenURI
call.
removeURIChangeActions()
This method can be called on a tag to remove all
whenURI
actions.
removeURIChangeAction(int index)
When the
whenURI
is called multiple times those actions will be indexed in the tag.
This method can be called on a tag to remove
whenURI
action at a particular index.
browserPage.setURI(String)
This method can be called at server side to change the URI of the app.
browserPage.setURI(String, boolean)
This method can be called at server side to replace the current
URI with the given one in the browser page history only if
true
is passed as the second argument. If
false
is passed as second argument then it changes the current uri with
the given one and adds to the browser history, i.e. browser page
navigates to the given uri, it is similar to calling
browserPage.setURI("/ui/user/items")
.
browserPage.getURI()
This method can be called at server side to get the current URI of the app.
browserPage.beforeURIChange(URIEvent
uriEvent)
This method can be overridden in the extended class of
BrowserPage
to mask the
uriBefore
value in the
URIEvent
object. Use case: This will be useful to improve security if third
party components are used in the application. If the uriBefore
contains some sensitive path param values and we don't want to let
any third party components to read such details then override this
method and return an
URIEventMask
with new
uriBefore
value.
Client side features
wffAsync.setURI
This function can be called at client side to change the URI of the app. There are four arguments for this function. The first argument is the uri to change, the second and third arguments are functions which will be invoked on uri change and after uri change respectively. The fourth argument is a boolean argument, if true is passed then the current uri in the browser page history will be replaced with the given uri (i.e. first argument). The second, third and fourth arguments are optional.
Checkout the following example
var uri = '/ui/user/items/view';
// the event object contains uriBefore and uriAfter properties
var preFunction = function(event) {
console.log('preFunction');
};
// the event object contains uriBefore, uriAfter and origin properties
var postFunction = function(event) {
console.log('postFunction');
};
// true to replace existing uri in the browser page history with the given uri passed
var replace = false;
// preFunction, postFunction and replace arguments are optional
wffAsync.setURI(uri, preFunction, postFunction, replace);
preFunction
will be invoked if there is a uri change, i.e. at time of calling
if the current uri is same as the uri value passed in
wffAsync.setURI
function then this function will not invoke. This will be useful
to show a progress icon only if there is a change in the URI.
postFunction
will be invoked only after the UI changes applied by the server,
this function may be used to stop the progress icon. If you want
to handle progress icon globally, you can use
wffGlobalListeners
. The fourth argument is
false
here i.e. not to replace the current uri in the browser history
instead navigate the page to the given uri.
wffGlobalListeners
wffGlobalListeners
, onSetURI
and afterSetURI
are
legal names used by the framework. It is not mandatory to have
wffGlobalListeners
in your js file. You can add the following code in the js file to
listen to URI change events.
const wffGlobalListeners = new function() {
// the event object contains uriBefore, uriAfter, origin and initiator properties
this.onSetURI = function(event) {
console.log('wffGlobalListeners > onSetURI', event);
loadingIcon.hidden = false;
};
// the event object contains uriBefore, uriAfter, origin and initiator properties
this.afterSetURI = function(event) {
console.log('wffGlobalListeners > afterSetURI', event);
loadingIcon.hidden = true;
};
};
wffGlobalListeners
,
onSetURI
and
afterSetURI
are optional.
event.uriBefore
is the uri before the uri change,
event.uriAfter
is the uri after uri change and
event.origin
will contain either
client
or
server
. If the
setURI
is called by client side JavaScript code (like
wffAsync.setURI
) then the
event.origin
will contain value as
client
and if the
setURI
is called by server side code (like
browserPage.setURI
) then the
event.origin
will contain value as
server
.
onSetURI
will be invoked only when there is a URI change at the time of
calling
wffAsync.setURI
function or
browserPage.setURI
method. Its role is similar to
preFunction
in
wffAsync.setURI
function.
afterSetURI
is invoked only after URI set and the UI changes applied by the
server. Its role is similar to
postFunction
in
wffAsync.setURI
function but in addition to that if
browserPage.setURI
is called at server side this function will get invoked.
The
initiator
can have value as
serverCode
,
clientCode
or
browser
. If the value is
serverCode
it means that the URI change is initiated by server side Java
code. If the value is
clientCode
it means that the URI change is initiated by client side
JavaScript code. If the value is
browser
it means that the URI change is initiated by some browser actions
such as browser's back/forward button (history buttons) click.
Note:
If the value of
initiator
is
browser
then the
uriBefore
property may not available.