3.5.13.3. Using URL History and Navigation API
This section contains examples of using the URL History and Navigation API.
Suppose we have a Task
entity and TaskInfo
screen with an information about a selected task.
The TaskInfo
screen controller contains the @Route
annotation to specify the route to the screen:
package com.company.demo.web.navigation;
import com.haulmont.cuba.gui.Route;
import com.haulmont.cuba.gui.screen.Screen;
import com.haulmont.cuba.gui.screen.UiController;
import com.haulmont.cuba.gui.screen.UiDescriptor;
@Route("task-info")
@UiController("demo_TaskInfoScreen")
@UiDescriptor("task-info.xml")
public class TaskInfoScreen extends Screen {
}
As a result, a user can open the screen by entering http://localhost:8080/app/#main/task-info
in the address bar:
When the screen is open, the address contains also a state mark.
- Mapping State to URL
-
Suppose that the
TaskInfo
screen shows information about a single task at a time, and it has controls to switch the selected tasks. You may want to reflect the currently viewed task in the URL to be able to copy the URL and later open the screen for this particular task just by pasting the URL to the address bar.The following code implements mapping of the selected task to the URL:
package com.company.demo.web.navigation; import com.company.demo.entity.Task; import com.google.common.collect.ImmutableMap; import com.haulmont.cuba.gui.Route; import com.haulmont.cuba.gui.UrlRouting; import com.haulmont.cuba.gui.components.Button; import com.haulmont.cuba.gui.components.LookupField; import com.haulmont.cuba.gui.screen.*; import com.haulmont.cuba.web.sys.navigation.UrlIdSerializer; import javax.inject.Inject; @Route("task-info") @UiController("demo_TaskInfoScreen") @UiDescriptor("task-info.xml") @LoadDataBeforeShow public class TaskInfoScreen extends Screen { @Inject private LookupField<Task> taskField; @Inject private UrlRouting urlRouting; @Subscribe("selectBtn") protected void onSelectBtnClick(Button.ClickEvent event) { Task task = taskField.getValue(); (1) if (task == null) { urlRouting.replaceState(this); (2) return; } String serializedTaskId = UrlIdSerializer.serializeId(task.getId()); (3) urlRouting.replaceState(this, ImmutableMap.of("task_id", serializedTaskId)); (4) } }
1 - get the current task from LookupField
2 - remove URL parameters if no task is selected 3 - serialize task’s id with the UrlIdSerializer
helper4 - replace the current URL state with the new one containing serialized task id as a parameter. As a result, the application URL is changed when the user selects a task and clicks the Select Task button:
- UrlParamsChangedEvent
-
Now let’s implement the last requirement: when a user enters the URL with the route and the
task_id
parameter, the application must show the screen with the corresponding task selected. Below is the complete screen controller code.package com.company.demo.web.navigation; import com.company.demo.entity.Task; import com.google.common.collect.ImmutableMap; import com.haulmont.cuba.core.global.DataManager; import com.haulmont.cuba.gui.Route; import com.haulmont.cuba.gui.UrlRouting; import com.haulmont.cuba.gui.components.Button; import com.haulmont.cuba.gui.components.LookupField; import com.haulmont.cuba.gui.navigation.UrlParamsChangedEvent; import com.haulmont.cuba.gui.screen.*; import com.haulmont.cuba.web.sys.navigation.UrlIdSerializer; import javax.inject.Inject; import java.util.UUID; @Route("task-info") @UiController("demo_TaskInfoScreen") @UiDescriptor("task-info.xml") @LoadDataBeforeShow public class TaskInfoScreen extends Screen { @Inject private LookupField<Task> taskField; @Inject private UrlRouting urlRouting; @Inject private DataManager dataManager; @Subscribe protected void onUrlParamsChanged(UrlParamsChangedEvent event) { String serializedTaskId = event.getParams().get("task_id"); (1) UUID taskId = (UUID) UrlIdSerializer.deserializeId(UUID.class, serializedTaskId); (2) taskField.setValue(dataManager.load(Task.class).id(taskId).one()); (3) } @Subscribe("selectBtn") protected void onSelectBtnClick(Button.ClickEvent event) { Task task = taskField.getValue(); if (task == null) { urlRouting.replaceState(this); return; } String serializedTaskId = UrlIdSerializer.serializeId(task.getId()); urlRouting.replaceState(this, ImmutableMap.of("task_id", serializedTaskId)); } }
1 - get the parameter value from UrlParamsChangedEvent
2 - deserialize the task id 3 - load the task instance and set it to the field