Using User-Defined Objects in UI5 Application
Prerequisites
Example User Defined Object (UDO) in AppEngine Plugin Project completed.
Description
After generating controllers, models, and serializers in User Defined Object (UDO) in AppEngine Plugin Project we will now adjust the ToDo view and controller on the frontend.
Fixing Binding in ToDo.view.xml
-
Open ToDo.view.xml
-
We need to change table binding:
- from FirstPlugin>/Todo to FirstPlugin>/ToDo
- we will remove $count and $$updateGroupId
items="{FirstPlugin>/ToDo}"
-
Now, let's fix columns and items definition
Add a new column for Task Description and appropriate translations to messages.xlm (you can find instructions here: Translations from backend)
<Column id="taskColumnDescription">
<Text text="{i18n>todoTableTaskColumnDescription}" />
</Column><Message id="todoTableTaskColumnDescription" param="0">
<translation lang="Default" Date="2011-08-09T15:55:59">
Description
</translation>
<translation lang="ln_English" Date="2011-08-09T15:55:59">
Description
</translation>
<translation lang="ln_Polish" Date="2011-08-09T15:55:59">
Opis
</translation>
</Message>- Add a new column for Priority and appropriate translations to messages.xlm
<Column id="taskColumnPriority" width="8em">
<Text text="{i18n>todoTableTaskColumnPriority}" />
</Column><Message id="todoTableTaskColumnPriority" param="0">
<translation lang="Default" Date="2011-08-09T15:55:59">
Priority
</translation>
<translation lang="ln_English" Date="2011-08-09T15:55:59">
Priority
</translation>
<translation lang="ln_Polish" Date="2011-08-09T15:55:59">
Priorytet
</translation>
</Message>- Change definition for ColumnListItem
<ColumnListItem>
<cells>
<ObjectStatus
icon="{= ${path: 'FirstPlugin>U_Priority', type: 'sap.ui.model.odata.type.String', formatter: '.getIconForPriority'}}"
state="{= ${path: 'FirstPlugin>U_Priority', type: 'sap.ui.model.odata.type.String', formatter: '.getStateForPriority'}}"
text="{= ${path: 'FirstPlugin>U_Priority', type: 'sap.ui.model.odata.type.String'}}"
/>
<CheckBox selected="{ path: 'FirstPlugin>U_Done', type: 'computec.appengine.ui.controls.YesNoBoolType'}" />
<Input value="{FirstPlugin>U_TaskName}" />
<Input value="{FirstPlugin>U_Description}" />
</cells>
<Button icon="sap-icon://delete" press=".onDelete"></Button>
</ColumnListItem> -
We will also remove the footer as we are now working in $auto submit mode.
-
Finally, the definition of our Todo.view.xml should look like this.
Todo.view.xml
<mvc:View
controllerName="computec.appengine.firstplugin.controller.Todo"
displayBlock="true"
xmlns="sap.m"
xmlns:mvc="sap.ui.core.mvc"
>
<Page showHeader="false">
<content>
<Table
id="todoList"
growing="true"
growingThreshold="10"
items="{FirstPlugin>/ToDo}"
fixedLayout="false"
>
<headerToolbar>
<OverflowToolbar>
<content>
<ToolbarSpacer />
<SearchField id="searchField" width="30%" search=".onSearch" />
<Button
id="addTaskButton"
icon="sap-icon://add"
press=".onCreate"
>
<layoutData>
<OverflowToolbarLayoutData priority="NeverOverflow" />
</layoutData>
</Button>
<Button
id="refreshTodoListButton"
icon="sap-icon://refresh"
press=".onRefresh"
/>
</content>
</OverflowToolbar>
</headerToolbar>
<columns>
<Column id="taskColumnPriority" width="8em">
<Text text="{i18n>todoTableTaskColumnPriority}" />
</Column>
<Column id="isDoneColumn" width="3rem">
<Text text="{i18n>todoTableIsDoneColumnTitle}" />
</Column>
<Column id="taskColumn" width="20em">
<Text text="{i18n>todoTableTaskColumnTitle}" />
</Column>
<Column id="taskColumnDescription">
<Text text="{i18n>todoTableTaskColumnDescription}" />
</Column>
<Column id="actions" width="3rem">
<Text text="" />
</Column>
</columns>
<items>
<ColumnListItem>
<cells>
<ObjectStatus
icon="{= ${path: 'FirstPlugin>U_Priority', type: 'sap.ui.model.odata.type.String', formatter: '.getIconForPriority'}}"
state="{= ${path: 'FirstPlugin>U_Priority', type: 'sap.ui.model.odata.type.String', formatter: '.getStateForPriority'}}"
text="{= ${path: 'FirstPlugin>U_Priority', type: 'sap.ui.model.odata.type.String'}}"
/>
<CheckBox selected="{ path: 'FirstPlugin>U_Done', type: 'computec.appengine.ui.controls.YesNoBoolType'}" />
<Input value="{FirstPlugin>U_TaskName}" />
<Input value="{FirstPlugin>U_Description}" />
</cells>
<Button icon="sap-icon://delete" press=".onDelete"></Button>
</ColumnListItem>
</items>
</Table>
</content>
</Page>
</mvc:View>
Adjusting Todo.controller.js
-
Beacuse we are using computec.appengine.ui.controls.YesNoBoolType, we need to add it to sap.ui.define
sap.ui.define([
"computec/appengine/core/BaseController",
"sap/ui/model/json/JSONModel",
"sap/m/MessageBox",
"sap/m/MessageToast",
"sap/ui/model/Sorter",
"sap/ui/model/Filter",
"sap/ui/model/FilterOperator",
"sap/ui/model/FilterType",
"computec/appengine/ui/controls/YesNoBoolType"
], function (BaseController, JSONModel, MessageBox, MessageToast,
Sorter, Filter, FilterOperator, FilterType, YesNoBoolType) { -
We need to fix the onCreate function. We will change the object definition in the oBinding.create method.
onCreate: function () {
var oList = this.byId("todoList"),
oBinding = oList.getBinding("items"),
oContext = oBinding.create({
U_Priority: 'Low',
U_Done: 'No'
});
oList.getItems().some(function (oItem) {
if (oItem.getBindingContext() === oContext) {
oItem.focus();
return true;
}
});
}, -
Also, the onSearch function can be expanded to search by Task Name and Description
onSearch: function () {
var oView = this.getView(),
sValue = oView.byId("searchField").getValue();
const aFilters = [];
if (typeof sValue === 'string' && sValue.length > 0) {
aFilters.push(new Filter({
path: 'U_TaskName',
operator: FilterOperator.Contains,
value1: sValue
}));
aFilters.push(new Filter({
path: 'U_Description',
operator: FilterOperator.Contains,
value1: sValue
}))
}
const oFilter = new Filter({
filters: aFilters,
and: false
});
oView.byId("todoList").getBinding("items").filter(oFilter);
}, -
We will remove the onSave, onInputChange, and _setUIChanges methods because we are now working in $auto submit mode.
-
We can also simplify the onInit method as we no longer need a view model.
onInit: function () {
BaseController.prototype.onInit.call(this);
this.setPageName("todoPageTitle");
}, -
Our formatter functions for Priority ObjectStatus control are shown below
-
getIconForPriority
getIconForPriority: function (sPriority) {
let sIcon;
switch (sPriority) {
case 'Low':
break;
case 'Medium':
sIcon = 'sap-icon://hint';
break;
case 'Huge':
sIcon = 'sap-icon://warning';
break;
default:
sIcon = null;
break;
}
return sIcon;
}, -
getStateForPriority
getStateForPriority: function (sPriority) {
let sState;
switch (sPriority) {
case 'Low':
break;
case 'Medium':
sState = 'Information';
break;
case 'Huge':
sState = 'Warning';
break;
default:
sState = 'None';
break;
}
return sState;
}
-
-
In result Todo.controller.js should look like this.
Todo.controller.js
sap.ui.define(
[
"computec/appengine/core/BaseController",
"sap/ui/model/json/JSONModel",
"sap/m/MessageBox",
"sap/m/MessageToast",
"sap/ui/model/Sorter",
"sap/ui/model/Filter",
"sap/ui/model/FilterOperator",
"sap/ui/model/FilterType",
"computec/appengine/ui/controls/YesNoBoolType",
],
function (
BaseController,
JSONModel,
MessageBox,
MessageToast,
Sorter,
Filter,
FilterOperator,
FilterType,
YesNoBoolType
) {
"use strict";
return BaseController.extend(
"computec.appengine.firstplugin.controller.Todo",
{
onInit: function () {
BaseController.prototype.onInit.call(this);
this.setPageName("todoPageTitle");
},
onCreate: function () {
var oList = this.byId("todoList"),
oBinding = oList.getBinding("items"),
oContext = oBinding.create({
U_Priority: "Low",
U_Done: "No",
});
oList.getItems().some(function (oItem) {
if (oItem.getBindingContext() === oContext) {
oItem.focus();
return true;
}
});
},
onDelete: function (oEvent) {
oEvent
.getSource()
.getBindingContext("FirstPlugin")
.delete("$auto")
.then(
function () {
MessageToast.show(
this.geti18n().getText("deletionSuccessMessage")
);
}.bind(this),
function (oError) {
MessageBox.error(oError.message);
}
);
},
onResetChanges: function () {
this.byId("todoList").getBinding("items").resetChanges();
},
onRefresh: function () {
var oBinding = this.byId("todoList").getBinding("items");
if (oBinding.hasPendingChanges()) {
this.byId("todoList").getBinding("items").resetChanges();
}
oBinding.refresh();
},
onSearch: function () {
var oView = this.getView(),
sValue = oView.byId("searchField").getValue();
const aFilters = [];
if (typeof sValue === "string" && sValue.length > 0) {
aFilters.push(
new Filter({
path: "U_TaskName",
operator: FilterOperator.Contains,
value1: sValue,
})
);
aFilters.push(
new Filter({
path: "U_Description",
operator: FilterOperator.Contains,
value1: sValue,
})
);
}
const oFilter = new Filter({
filters: aFilters,
and: false,
});
oView.byId("todoList").getBinding("items").filter(oFilter);
},
getIconForPriority: function (sPriority) {
let sIcon;
switch (sPriority) {
case "Low":
break;
case "Medium":
sIcon = "sap-icon://hint";
break;
case "Huge":
sIcon = "sap-icon://warning";
break;
default:
sIcon = null;
break;
}
return sIcon;
},
getStateForPriority: function (sPriority) {
let sState;
switch (sPriority) {
case "Low":
break;
case "Medium":
sState = "Information";
break;
case "Huge":
sState = "Warning";
break;
default:
sState = "None";
break;
}
return sState;
},
}
);
}
);
Results
After these changes, To Do view will work with our newly generated controllers for To Do User Defined Objects. We can now search, add, delete and change them. All changes are automatically send to backend to be saved.