You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: packages/fiori-docs-embeddings/data_local/fiori_extension_instructions.md
+297-5Lines changed: 297 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -45,6 +45,34 @@ Replace all placeholder names with your actual values:
45
45
46
46
**CRITICAL PITFALL 14 — Must `return oDialog` from the `.then()` callback inside `Fragment.load().then()`**: When storing a Fragment.load Promise as `this._pRelatedEntityDialog`, the `.then()` callback where `oView.addDependent(oDialog)` is called MUST end with `return oDialog`. If omitted, the Promise resolves to `undefined` (the implicit return value). All subsequent calls like `this._pRelatedEntityDialog.then(function(oDialog) { oDialog.open(); })` will then receive `undefined` as `oDialog` — `oDialog.open()` silently fails or throws `TypeError: Cannot read properties of undefined`. This is the single most common silent failure in the Fragment.load Promise pattern. Always write: `.then(function(oDialog) { oView.addDependent(oDialog); return oDialog; })`. As a related convention: prefix all Promise-stored dialog references with `_p` (e.g. `_pRelatedEntityDialog`, `_pAgencyPopup`) to visually distinguish them from direct object references — this makes it immediately clear that `.then()` must be used to access the dialog.
47
47
48
+
**CRITICAL PITFALL 15 — `sap.fe.macros.Field` renders in display-only mode in a `Fragment.load()` dialog that is NOT bound to an OData context**: When a dialog loaded via `Fragment.load()` binds its fields to a JSON model (not an OData model), `sap.fe.macros.Field` building blocks render in display-only mode regardless of `editMode="Editable"`. The building block relies on the Fiori Elements OData model context to resolve and apply edit mode at runtime — without an OData binding context on the dialog or a parent view context, the field stays read-only and user input is not possible. **Fix**: For data-entry dialogs where field values are stored in a JSON model (not read from OData), replace `macros:Field` with standard `sap.m` controls: use `sap.m.Input` for string/text fields (TravelID, AgencyID, etc.) and `sap.m.DatePicker` for date fields. `sap.m.DatePicker` with `valueFormat="yyyy-MM-dd"` and `displayFormat="mediumDate"` provides locale-aware date formatting and a calendar dropdown picker out of the box — no OData context required. Note: `macros:Field` CAN work in dialogs that are properly `bindElement()`-bound to an OData entity path (as in the read-only popup pattern above) when the field is being read from OData, but NOT when the field value is bound only to a JSON model.
49
+
50
+
**CRITICAL PITFALL 16 — The correct manifest.json location for Object Page header toolbar custom actions is `content.header.actions` inside `options.settings`, NOT `controlConfiguration.headerActions`**: To add a custom button to the Object Page header toolbar, add it under `options.settings.content.header.actions` in the Object Page routing target configuration. Each action is a key under `actions` with `press`, `text`, `enabled`, and `visible` properties. The `press` value uses the `.extension.<namespace>.<ControllerName>.<methodName>` format (same as other FE-managed view handlers). Using `controlConfiguration.headerActions`, `controlConfiguration.content.header.actions`, or any other path will silently fail — no button appears in the header, no error is thrown. Correct structure:
**STEP 1**: Register the custom column in manifest.json
@@ -711,15 +739,15 @@ sap.ui.define([
711
739
712
740
--------------------------------
713
741
714
-
**TITLE**: Custom Popup for Data Entry using Field Building Block and JSON Model
742
+
**TITLE**: ⚠️ BROKEN — Custom Popup for Data Entry using macros:Field and JSON Model (Wrong manifest path + fields render display-only)
715
743
716
-
**INTRODUCTION**: This guide explains how to add a button to the Object Page header toolbar that opens a custom popup dialog for data entry. The popup uses sap.fe.macros.Field building blocks bound to a local JSON model, allowing the user to input travel merge parameters. This pattern is useful for custom actions requiring user input before calling an OData action or performing programmatic operations.
744
+
**INTRODUCTION**: ⚠️ THIS PATTERN HAS TWO CRITICAL BUGS and is documented here for error recognition only. Do not use it. See the verified working pattern below instead. Bug 1: The manifest.json action is registered under `controlConfiguration.headerActions` — this path does not exist and the button never appears. The correct path is `content.header.actions` inside `options.settings` (see Pitfall 16). Bug 2: The fragment uses `sap.fe.macros.Field`bound to a JSON model — these fields render in display-only mode because `macros:Field` requires an OData binding context to activate edit mode (see Pitfall 15). As a result all input fields are read-only and users cannot enter any data.
717
745
718
-
**TAGS**: custom popup, data entry, Field building block, sap.fe.macros.Field, object page, header toolbar, toolbar button, JSON model, controller extension, fragment, dialog, custom action, extension, building blocks
746
+
**TAGS**: custom popup, data entry, Field building block, sap.fe.macros.Field, object page, header toolbar, toolbar button, JSON model, controller extension, fragment, dialog, custom action, extension, building blocks, BROKEN, DO NOT USE
719
747
720
748
**STEP**: Register the Object Page header action in manifest.json
721
749
722
-
**DESCRIPTION**: Add a custom action to the `controlConfiguration` for the Object Page header. The action triggers a controller extension method that opens the popup dialog.
750
+
**DESCRIPTION**: ⚠️ WRONG PATH — `controlConfiguration.headerActions` does not work. See Pitfall 16 and the verified working pattern below for the correct `content.header.actions` path.
723
751
724
752
**LANGUAGE**: JSON
725
753
@@ -1123,4 +1151,268 @@ sap.ui.define([
1123
1151
}
1124
1152
```
1125
1153
1126
-
--------------------------------
1154
+
--------------------------------
1155
+
1156
+
**TITLE**: Object Page Header Toolbar Button → Data Entry Popup with Standard Controls (Input, DatePicker) ✅ VERIFIED WORKING PATTERN
1157
+
1158
+
**INTRODUCTION**: This guide explains how to add a custom button to the Object Page header toolbar that opens a data-entry popup dialog. The popup uses standard `sap.m` controls — `sap.m.Input` for text/string fields and `sap.m.DatePicker` for date fields — bound to a local JSON model. This is the correct pattern when field values are stored in a JSON model (not OData). Do NOT use `sap.fe.macros.Field` for this use case — those building blocks render display-only when not backed by an OData binding context (see Pitfall 15). Do NOT register the action under `controlConfiguration.headerActions` — the correct path is `content.header.actions` (see Pitfall 16).
1159
+
1160
+
Replace all placeholder names with your actual values:
1161
+
-`my.app` → your app namespace (e.g. `fin.test.rap.lr3`)
1162
+
-`ObjectPageExt` → your Object Page controller extension name
1163
+
-`MyEntityObjectPage` → your Object Page routing target name
1164
+
-`MyEntity` → your OData entity set name
1165
+
1166
+
**TAGS**: custom popup, data entry, object page, header toolbar, toolbar button, JSON model, sap.m.Input, sap.m.DatePicker, DatePicker, date picker, controller extension, fragment, dialog, custom action, extension, standard controls, verified working
1167
+
1168
+
---
1169
+
1170
+
**STEP 1**: Register the header toolbar action in manifest.json
1171
+
1172
+
**DESCRIPTION**: Add the action under `options.settings.content.header.actions` in the Object Page routing target. This is the ONLY correct location — `controlConfiguration.headerActions` silently fails (Pitfall 16). The `press` handler uses the full `.extension.<namespace>.<ControllerName>.<methodName>` format because the Object Page view is FE-managed (Pitfall 2). Replace `my.app`, `ObjectPageExt`, `MyEntityObjectPage`, and `MyEntity` with your actual values.
1173
+
1174
+
**FILE**: webapp/manifest.json (inside the Object Page routing target)
**DESCRIPTION**: Use `sap.m.Input` for string fields and `sap.m.DatePicker` for date fields. Key rules: (1) `sap.m.DatePicker` requires `valueFormat` matching the OData date format (`yyyy-MM-dd`) and `displayFormat="mediumDate"` for locale-aware user-facing formatting — this also activates the calendar dropdown picker. (2) All button press handlers use direct dot-prefix `.onXxx` — NOT `.extension.XXX.onXxx` — because the fragment is loaded via `Fragment.load()` with `controller: this` (Pitfall 2). (3) All controls in the dialog need stable `id` attributes because `flexEnabled: true` (Pitfall 3). (4) Use `xmlns:form="sap.ui.layout.form"` and `<form:SimpleForm>` with `<form:content>` aggregation for the form layout.
<!-- MUST use direct .onConfirm — NOT .extension.XXX.onConfirm (Pitfall 2) -->
1285
+
<Button
1286
+
id="dataEntryConfirmBtn"
1287
+
text="{i18n>confirmButton}"
1288
+
type="Emphasized"
1289
+
press=".onConfirmDataEntry" />
1290
+
</beginButton>
1291
+
<endButton>
1292
+
<!-- MUST use direct .onCloseDataEntryPopup — NOT .extension.XXX.onCloseDataEntryPopup (Pitfall 2) -->
1293
+
<Button
1294
+
id="dataEntryCancelBtn"
1295
+
text="{i18n>cancelButton}"
1296
+
press=".onCloseDataEntryPopup" />
1297
+
</endButton>
1298
+
</Dialog>
1299
+
</core:FragmentDefinition>
1300
+
```
1301
+
1302
+
**STEP 4**: Create the controller extension
1303
+
1304
+
**DESCRIPTION**: Key rules: (1) Use `this.base.getView()` — NOT `this.getView()` — in a ControllerExtension (Pitfall 6). (2) Initialise the JSON model (`entryModel`) in `onInit` using `this.base.getView().setModel()`. (3) Use `Fragment.load()` with a unique id suffix to avoid control ID conflicts (Pitfall 8). (4) Always `return oDialog` from the `.then()` callback (Pitfall 14). (5) Guard `onCloseDataEntryPopup` with `if (this._pDataEntryPopup)` to avoid errors if called before the fragment is ever loaded. (6) Pre-populate fields from the current Object Page context inside `onOpenDataEntryPopup` using `oView.getBindingContext().getProperty("FieldName")`.
0 commit comments