Selection Screen
A classic input mask with combobox, DatePicker, checkbox, switch — comparable to an ABAP SELECTION-SCREEN. Shows the pattern for structured app fields (s_screen as a container) and how you bind sub-paths within a structure.
Code
js
// srv/samples/selection_screen.js
const z2ui5_if_app = require("../z2ui5/02/z2ui5_if_app");
const z2ui5_cl_xml_view = require("../z2ui5/02/z2ui5_cl_xml_view");
class selection_screen extends z2ui5_if_app {
s_screen = {
check_is_active: false,
colour: "",
combo_key: "",
segment_key: "",
date: "",
date_time: "",
time_start: "",
time_end: "",
check_switch_01: false,
check_switch_02: false,
};
t_suggestions = [];
t_combo = [];
async main(client) {
if (client.check_on_init()) {
this.on_init();
this.render(client);
return;
}
if (client.check_on_event()) {
this.on_event(client);
this.render(client);
}
}
on_init() {
this.s_screen = {
check_is_active: true,
colour: "BLUE",
combo_key: "GRAY",
segment_key: "GREEN",
date: "2025-12-07",
date_time: "2025-12-23T19:27:20",
time_start: "05:24:00",
time_end: "17:23:57",
check_switch_01: false,
check_switch_02: false,
};
this.t_suggestions = [
{ descr: "Green", value: "GREEN" },
{ descr: "Blue", value: "BLUE" },
{ descr: "Black", value: "BLACK" },
{ descr: "Gray", value: "GRAY" },
];
this.t_combo = [
{ key: "BLUE", text: "blue" },
{ key: "GREEN", text: "green" },
{ key: "BLACK", text: "black" },
{ key: "GRAY", text: "gray" },
];
}
on_event(client) {
switch (client.get().EVENT) {
case "BUTTON_SEND":
client.message_box_display("Values sent to the server");
break;
case "BUTTON_CLEAR":
for (const k of Object.keys(this.s_screen)) {
this.s_screen[k] = typeof this.s_screen[k] === "boolean" ? false : "";
}
client.message_toast_display("View reset");
break;
}
}
render(client) {
const view = z2ui5_cl_xml_view.factory();
const page = view.Shell().Page({
title: "abap2UI5 - Selection Screen",
navButtonPress: client._event_nav_app_leave(),
showNavButton: client.check_app_prev_stack(),
});
// 1) pull out the path to s_screen → manually build sub-paths
const screenPath = client._bind_edit(this.s_screen, { path: true });
const screen = (k) => `{${screenPath}/${k}}`;
const grid = page.Grid({ defaultSpan: "L6 M12 S12" }).content();
const sf1 = grid.SimpleForm({ title: "Input", editable: true }).content();
sf1.Label({ text: "Color (with suggestions)" });
sf1.Input({
value: screen("colour"),
placeholder: "Enter your favorite color",
suggestionItems: client._bind(this.t_suggestions),
showSuggestion: true,
}).get().suggestionItems().ListItem({ text: "{value}", additionalText: "{descr}" });
const sf2 = grid.SimpleForm({ title: "Time Inputs", editable: true }).content();
sf2.Label({ text: "Date" }).DatePicker({ value: screen("date") });
sf2.Label({ text: "Date / Time" }).DateTimePicker({ value: screen("date_time") });
sf2.Label({ text: "Time Start / End" });
sf2.TimePicker({ value: screen("time_start") });
sf2.TimePicker({ value: screen("time_end") });
const content = page.Grid({ defaultSpan: "L12 M12 S12" })
.content()
.SimpleForm({ title: "Selection", editable: true })
.content();
content.Label({ text: "Active" });
content.CheckBox({ selected: screen("check_is_active"), text: "Active", enabled: true });
content.Label({ text: "Combo" });
content.ComboBox({
selectedKey: screen("combo_key"),
items: client._bind(this.t_combo),
}).Item({ key: "{key}", text: "{text}" });
content.Label({ text: "Segmented" });
content.SegmentedButton({ selectedKey: screen("segment_key") })
.items()
.SegmentedButtonItem({ key: "BLUE", icon: "sap-icon://accept", text: "blue" })
.SegmentedButtonItem({ key: "GREEN", icon: "sap-icon://add-favorite", text: "green" })
.SegmentedButtonItem({ key: "BLACK", icon: "sap-icon://attachment", text: "black" });
content.Label({ text: "Switch 1" }).Switch({ state: screen("check_switch_01") });
content.Label({ text: "Switch 2" }).Switch({ state: screen("check_switch_02") });
const footer = page.footer().OverflowToolbar();
footer.ToolbarSpacer();
footer.Button({ text: "Clear", press: client._event("BUTTON_CLEAR"), type: "Reject", icon: "sap-icon://delete" });
footer.Button({ text: "Send", press: client._event("BUTTON_SEND"), type: "Success" });
client.view_display(view.stringify());
}
}
module.exports = selection_screen;The sub-path pattern
The most important trick:
js
const screenPath = client._bind_edit(this.s_screen, { path: true });
// ^^^^^^^^^^^
// "give me the bare path,
// not wrapped in {...}"
const screen = (k) => `{${screenPath}/${k}}`;
// screen("colour") === "{/XX/s_screen/colour}"_bind_edit(this.s_screen) returns the path to the entire structure object via reference equality. With { path: true } you get it unwrapped — and can then append sub-paths yourself.
This saves you from binding every sub-field individually — a single lookup, many bindings.
Two BUTTON_* events in a switch
In on_event() the pattern shows up when you have many events — a switch over client.get().EVENT is usually more readable than ten if (check_on_event(...)) blocks.
→ Continue to List & Detail.