1. Domino History
  2. Wildcards

Wildcards

Token filters allow us to listen to specific changes in the URL, and when a filter returns true a listener that is associated with the filter will be called, in which we receive a state that represent the current URL allowing us to make some check and do some logic based on the URL new value. so what if we have some common logic between different matches for similar URLs and we dont want to duplicate the listeners? for example, We want to a payment record, but based on the user department he might see a different view with different kind of details of that payment, accountant department vs audit department vs reporting department, in this case we could something like this :

			stateHistory.listen(TokenFilter.startsWithPathFilter("payments/accountant"), state -> {
    String paymentId = state.token().getQueryParameter("paymentId").get(0);
    viewPayment("accountant", paymentId);
});

stateHistory.listen(TokenFilter.startsWithPathFilter("payments/audit"), state -> {
    String paymentId = state.token().getQueryParameter("paymentId").get(0);
    viewPayment("audit", paymentId);
});

stateHistory.listen(TokenFilter.startsWithPathFilter("payments/reporting"), state -> {
    String paymentId = state.token().getQueryParameter("paymentId").get(0);
    viewPayment("reporting", paymentId);
});
		

Now even though this can work, but in case we have a new department we will not only need to change the implementation of the viewPayment method, but also will need to add a new listener to call the method with the new department, which indeed not something we want to have in our code, domino-rest have the solution for this by allowing the use of expressions in the token filters matching tokens, so for example we can write the above like the following instead:

			stateHistory.listen(TokenFilter.startsWithPathFilter("payments/:department"), state -> {
    List<String> paymentId = state.token().getQueryParameter("paymentId");
    String department = state.normalizedToken().getPathParameter("department");
    viewPayment(department, paymentId);
});
		

Now instead of a specific token in the filter matching string we have a string with an expression :department, then from the state we used the normalizedToken to get the actual value of the department received from the new URL value, and notice how the key we used matches the expression in the token without the :. So what is a normalized token?

A NormalizedToken is a version of the state that has been produced from the matching of the new URL value with the string token specified by the token filter, then it try to actually match each expression and assign its value from the URL, in the example above, if we matched payments/:department with payments/accountant for example, then the first path element is not an expression is a true match between both the tokens, then the :department which is the second path element is matched with accountant, and since it an expression it will be a true match then will be added to the normalized token and a path parameter with the key department and value accountant

This kind of expression matching works great for most of the cases, but it cant be applied for all kind of filters, for example a containsPath filter will be very hard to match with expressions, this is because we are matching any part of the URL that could be in the start, the end the middle or anywhere in the URL so we cant just assume the value of the expression will match what could be randomly located in the URL, this kind of filters like the containsPath one are deemed to have this kind of restriction, and we implement our own custom TokenFilters we need also to keep in mind that our implementation might not support the use of expression.

Last but least expressions also works for fragments, which is very useful for within same page navigation, for example we can force the page to scroll to a specific section by change the fragments part of the url while listening to the change with expressions, for example :

			stateHistory.listen(TokenFilter.startsWithFragment(":section"), state -> {
    String section = state.normalizedToken().getFragmentParameter("section");
    scrollTo(section);
});
		

We are a group of passionate people who love what we do

Donate & Support Us