> For the complete documentation index, see [llms.txt](https://hal-console.gitbook.io/elemento/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://hal-console.gitbook.io/elemento/router.md).

# Router

Elemento offers a very basic router. The router is minimally invasive and built around a few simple concepts:

* `Place`\
  Data class that represents a place in an application. A place is identified by a route and can have an optional title and a custom root element. Routes can have parameters such as in `/contacts/:contactId`. Finally, a place can also have a loader assigned to it.
* `Places`\
  Builder to set up places. It supports nested places, combines places, and assigns loaders to places.
* `LoadData<T>`\
  Functional interface to asynchronously load data before a page is created and added to the DOM. The function gets the place and parameters as input, returns a promise of the data to be loaded, and is defined as `Promise<T> load(Place place, Parameter parameter)`.
* `Page`\
  Simple interface that represents a collection of HTML elements. Implementations should be cheap to create and need to implement a single method: `Iterable<HTMLElement> elements(Place, Parameter, LoadedData)`.
* `PlaceManager`\
  Main class of the router module. Performs the following tasks, among others:
  * keeps track of registered places
  * handles navigation events
  * parses route parameters
  * calls loader functions
  * updates the DOM and browser history

The place manager can be customized using builder-like methods and has a `start()` method to show the initial page.

## Annotations

Creating a `Place` instance can be time-consuming (especially in large applications). This can be automated by using annotations, where an annotation processor takes over the tedious work of creating the `Place` instances. You can use the following annotations for this purpose:

* `@Route`\
  Annotation to mark a `Page` implementation as a place. The annotation requires a route and can have an optional title, root selector, and reference to a named loader. If the annotated page has **exactly one** public, static method that returns `LoadData<?>` and accepts no parameters, this is used as a loader for the place. If a loader is specified using the `loader` attribute, there has to be a matching class or static method annotated with `@Loader`.
* `@Loader`\
  Annotation to mark a class or public static method as a named loader. If used on a class, the class has to implement `LoadData<T>`. If used on a static method, the method must return `LoadData<?>` and not accept any parameters.

You can also mix and match your own `Places` instance with the generated one (see below).

## URL Encoding

Route parameter values that contain special URL characters (`/`, `?`, `#`, `&`, `=`, spaces) are handled transparently by the router.

### Automatic Encoding

Use the overloaded `goTo()`, `href()`, and `Link.link()` methods that accept a route template and parameter values. Pass raw/decoded values — encoding is handled internally:

```java
// Navigate with encoded parameters
placeManager.goTo("/resource/:name", "my/file");
placeManager.goTo("/time/:area/:location", "America", "New_York");

// Generate href with encoded parameters
String url = placeManager.href("/resource/:name", "my/file");

// Create a link with encoded parameters
Link.link(placeManager, "/resource/:name", "my/file");
```

### Manual Encoding

When building paths yourself for use with `goTo(String path)` or `href(String path)`, use the encoding utilities:

```java
// Build an encoded path from a template
String path = Parameter.encodePath("/resource/:name", "my/file");
// → "/resource/my%2Ffile"
placeManager.goTo(path);

// Encode a single value
String encoded = Parameter.encode("my/file"); // → "my%2Ffile"
```

### Reading Parameters

`Parameter.get()` always returns **decoded** values. Use `Parameter.getRaw()` for the raw/encoded form:

```java
parameter.get("name")    // → "my/file" (decoded)
parameter.getRaw("name") // → "my%2Ffile" (encoded)
```

### Encoding Behavior by Method

| Method                                   | Encoding behavior                 |
| ---------------------------------------- | --------------------------------- |
| `Parameter.encode(value)`                | Encodes a raw value → URL-safe    |
| `Parameter.decode(value)`                | Decodes a URL-encoded value → raw |
| `Parameter.encodePath(route, values...)` | Encodes values automatically      |
| `Parameter.get(name)`                    | Returns **decoded** value         |
| `Parameter.getRaw(name)`                 | Returns **encoded** value         |
| `Parameter.getOrDefault(name, default)`  | Returns **decoded** value         |
| `PlaceManager.goTo(route, values...)`    | Encodes values automatically      |
| `PlaceManager.goTo(path)`                | No encoding — path used as-is     |
| `PlaceManager.href(route, values...)`    | Encodes values automatically      |
| `PlaceManager.href(path)`                | No encoding — path used as-is     |
| `Link.link(pm, route, values...)`        | Encodes values automatically      |
| `Link.link(pm, route)`                   | No encoding — route used as-is    |

## Optional Parameters

Routes can have optional parameters using the `:param?` syntax (trailing `?`). Optional parameters must be at the end of the route. A route like `/users/:id?` matches both `/users` and `/users/123`.

### Rules

* Optional parameters use the `:name?` syntax
* Optional parameters must be trailing — `/users/:id?/edit` is **invalid**
* Multiple trailing optional parameters are allowed: `/a/:b?/:c?`
* Required parameters can precede optional ones: `/a/:b/:c?`

### Example

```java
@Route("/users/:id?")
public class UsersPage implements Page {

    @Override
    public Iterable<HTMLElement> elements(Place place, Parameter parameter, LoadedData data) {
        if (parameter.has("id")) {
            // show single user
            String id = parameter.get("id");
            return asList(h(1, "User " + id).element());
        } else {
            // show user list
            return asList(h(1, "All Users").element());
        }
    }
}
```

### Navigation

```java
// Navigate to the user list (optional param omitted)
placeManager.goTo("/users");

// Navigate to a specific user (optional param provided)
placeManager.goTo("/users/:id?", "123");

// Build paths with optional params
Parameter.encodePath("/users/:id?");         // → "/users"
Parameter.encodePath("/users/:id?", "123");  // → "/users/123"
Parameter.encodePath("/a/:b/:c?", "1");      // → "/a/1"
Parameter.encodePath("/a/:b/:c?", "1", "2"); // → "/a/1/2"
```

## Sample

Here's an example showing most of the concepts in action:

```java
@Route("/time/:area/:location")
public class TimePage implements Page {

    // This is used as the loader for the place
    public static LoadData<String> loadTime() {
        return (place, parameter) -> {
            String area = parameter.get("area");
            String location = parameter.get("location");
            String url = "https://worldtimeapi.org/api/timezone/" + area + "/" + location;
            return fetch(url)
                    .then(Response::json)
                    .then(json -> {
                        JsPropertyMap<String> map = Js.cast(json);
                        return Promise.resolve(map.get("datetime"));
                    });
        };
    }

    @Override
    public Iterable<HTMLElement> elements(Place place, Parameter parameter, LoadedData data) {
        String area = parameter.get("area");
        String location = parameter.get("location");
        String currentTime = data.get();
        return asList(
                h(1, "Current time").element(),
                p()
                        .add("It's ")
                        .add(span().text(currentTime))
                        .add(" in " + area + "/" + location)
                        .element());
    }
}

@Route(value = "/", title = "Home")
public class HomePage implements Page {

    @Override
    public Iterable<HTMLElement> elements(Place place, Parameter parameter, LoadedData data) {
        return asList(
                h(1, "Welcome").element(),
                p()
                        .add("What time is it in ")
                        .add(a("/time/Europe/Berlin").textNode("Berlin"))
                        .add("?")
                        .element());
    }
}

public class Application {

    public void entryPoint() {
        body().add(div().id("main"));

        Places allPlaces = places()
                .add(new AnnotatedPlaces()) // generated places instance
                .add(place("/foo"), FooPage::new)
                .add(place("/bar"), BarPage::new)
                .children("/level1", places()
                        .add(place("/"), Level1Page::new) // index page
                        .add(places() // siblings
                                .add(place("/foo"), Foo1Page::new)
                                .add(place("/bar"), Bar1Page::new))
                        .children("/level2", places()
                                .add(place("/foo"), Foo2Page::new)
                                .add(place("/bar"), Bar2Page::new)));

        PlaceManager placeManager = new PlaceManager()
                .root(By.id("main"))
                .register(allPlaces);
        placeManager.start();
    }
}
```

See the API documentation of [PlaceManager](https://hal.github.io/elemento/apidocs/org/jboss/elemento/router/PlaceManager.html) for more details.

## Dependency

Add the following dependency to use `elemento-router`:

```xml
<dependency>
    <groupId>org.jboss.elemento</groupId>
    <artifactId>elemento-router</artifactId>
    <version>2.5.2</version>
</dependency>
```

In your GWT module, inherit from `org.jboss.elemento.Router`:

```xml
<module>
    <inherits name="org.jboss.elemento.Router"/>
</module>
```
