SAPUI5 odata binding for deep structure to vbox items - sapui5

JSON data:
{
"QuestionID": 1,
"Question": "Question One",
"Note": "Note: There are 2 correct answers to this question.",
"Type": "C",
"Answers": [
{
"Id": 1,
"Text": "Choice 1"
}, {
"Id": 2,
"Text": "Choice 2"
}, {
"Id": 3,
"Text": "Choice 3"
}, {
"Id": 4,
"Text": "Choice 4"
}
]
}
In my view I get the correct number of checkboxes for the answers but the "Text" does not show.
`<VBox id='checkBoxes' items="{Answers}">
<items>
<CheckBox text='{Text}' selected='{selected}' />
</items>
</VBox>`
Any assistance in how to bind the properties for the Answers will be appreciated.

In your VBox view code, ensure you have templateShareable:false. Then your nested binding will work like a charm.
Here's an example:
View
<CustomListItem>
<VBox class="sapUiSmallMargin">
<HBox justifyContent="SpaceBetween" class="sapUiTinyMarginBottom sapUiTinyMarginEnd">
<Title text="{noteAttach>CreatorName}" />
<Text text="{parts:[{path:'noteAttach>NotesType'},{path:'noteAttach>CreatedOn'}], formatter:'.formatter.formattedDate'}" />
</HBox>
<Text class="sapUiTinyMarginBottom" text="{noteAttach>NotesData}" />
<VBox items="{path:'noteAttach>Files', templateShareable:false}">
<HBox>
<core:Icon class="sapUiTinyMarginEnd" src="{path:'noteAttach>DocType', formatter:'.formatter.customFileIcon'}" />
<Link href="{parts:[{path:'noteAttach>ObjectId'},{path:'noteAttach>Viewname'},{path:'noteAttach>Title'}], formatter:'.formatter.fileDownloadHref'}" target="_blank" text="{path:'noteAttach>Title'}" />
</HBox>
</VBox>
</VBox>
</CustomListItem>
Controller (for those who also have to modify the OData they receive from backend, like I had to)
this.getOwnerComponent().getModel('noteAttach').read("/NotesandattachmentSet", {
filters: aFilters,
success: function(oData) {
/*
the reason why we create a new object property called Files and in it store an unnumbered Title is bc of the need to do binding with deep/nested structures
if we dont do this, we end up with up to 10 slots of white space for each entry. this is the only way to do this. all other methods mess up search, sort, and filter functionalities
*/
var aODataResults = oData.results;
var iODataResultsLength = aODataResults.length;
for (var j = 0; j < iODataResultsLength; j++) { //sift through each DataEntry in the model
var aObjectFiles = aODataResults[j].Files = []; //create 'Files' property in each object entry
for (var i = 1; i < 11; i++) { //in each DataEntry, find ppty Title1,Title2...up to Title10 & remove the ppties thatre empty. if not empty, create a downloadLink & icon for it
var sObjectFileTitle = aODataResults[j]["Title" + i];
if (sObjectFileTitle.length !== 0) aObjectFiles.push({
Title: sObjectFileTitle,
DocType: aODataResults[j]["DocType" + i],
ObjectId: aODataResults[j]["ObjectId"],
Viewname: aODataResults[j]["Viewname"],
});
}
}
that.getView().setModel(new JSONModel(aODataResults), "noteAttach");
that.getView().setBusy(false);
},
error: function(oError) {
that.parseErrorMessage(oError);
that.getView().setBusy(false);
}
How My Model Looks Like:
How She Looks:

Related

Stable ID for sap.tnt.NavigationListItem (id vs. key)

According to the Use Stable IDs article, it is recommended to use stable IDs for the UI5 elements. At the same time, I've reviewed multiple samples of sap.tnt.NavigationListItem implementation and I've paid attention that in case of sap.tnt.NavigationListItem no id is used but key, e.g.:
<tnt:NavigationListItem text="{name}" icon="{icon}" key="{controller}" select="onItemSelect" />
I've also tried to assign id to tnt:NavigationListItem and then access it from the oEvent-object via the standard oEvent.getProperty("%MY_ID%") approach but no success.
My questions:
When should I use id and when key for UI5-items in XML-templates?
Is it particular sap.tnt.NavigationListItem case that key is preferred over id or I just missed something important?
Based on your comments, I made a small example.
If your items are hard-coded definitely go for the key in the
XML definition.
If your items come over a model. You can do the same
as everywhere else. Use the data to trigger the right action.
Use the ID if you need to identify the UI element e.g. buttons in a test or if you add User Assistance Help.
sap.ui.controller("view1.initial", {
onInit: function(oEvent) {
this.getView().setModel(
new sap.ui.model.json.JSONModel({
items: [{
title : "1",
subItems: [
{ keyInData: "1", title : "1-a" },
{ keyInData: "2", title : "1-b" },
{ keyInData: "3", title : "1-c" },
{ keyInData: "4", title : "1-d" }
]
}],
}));
},
onItemSelect: function(oEvent) {
const item = oEvent.getParameter("item")
console.log("key over key binding: " + item.getKey() )
console.log("key over databinding: " + item.getBindingContext().getObject().keyInData )
}
});
sap.ui.xmlview("main", { viewContent: jQuery("#view1").html() } ).placeAt("uiArea");
<script id="sap-ui-bootstrap"
src="https://sapui5.hana.ondemand.com/resources/sap-ui-core.js"
data-sap-ui-theme="sap_bluecrystal"
data-sap-ui-xx-bindingSyntax="complex"
data-sap-ui-compatVersion="edge"
data-sap-ui-libs="sap.m"></script>
<div id="uiArea"></div>
<script id="view1" type="ui5/xmlview">
<mvc:View controllerName="view1.initial" xmlns="sap.m" xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc" xmlns:tnt="sap.tnt">
<tnt:NavigationList
id="navigationList"
width="320px"
selectedKey="subItem3" items="{/items}">
<tnt:NavigationListItem text="{title}" items="{ path:'subItems', templateShareable:false}" icon="sap-icon://employee" >
<tnt:NavigationListItem text="{title} - {keyInData}" key="{keyInData}" select="onItemSelect" />
</tnt:NavigationListItem>
</tnt:NavigationList>
</mvc:View>
</script>

SAPUI5 Smartable not showing the inital fields

I am trying to build a simple smarttable, using a CDS with annotation, I expect the columns to be displayed automatically but no column or selection field are displayed automatically. When I try to create a report with fiori element it is working fine but not with my freestyle app and smarttable. What is missing ?
#AbapCatalog.sqlViewName: 'ZTEST_CDS_SHP'
#AbapCatalog.compiler.compareFilter: true
#AbapCatalog.preserveKey: true
#AccessControl.authorizationCheck: #CHECK
#EndUserText.label: 'Test Shipment view'
#VDM.viewType: #CONSUMPTION
#VDM.private:false
#Search.searchable: true
#UI.headerInfo: { typeName: 'Order', typeNamePlural: 'Orders' }
#OData.publish: true
define view ZTESTV_CDS_SHP as select from ZRDCV_CDS_SHIPMENT
association [0..1] to ZTESTV_CDS_DCHELP as _DCValueHelp on $projection.DcSite = _DCValueHelp.Werks
association [0..1] to makt as _ArticleValueHelp on $projection.Article = _ArticleValueHelp.matnr and _ArticleValueHelp.spras = $session.system_language
{
#Search.defaultSearchElement: true
#UI.selectionField: [ { position: 10 } ]
#UI.lineItem: [ { position: 10, importance: #HIGH } ]
key shipment as Shipment,
#UI.selectionField: [ { position: 20 } ]
#UI.lineItem: [ { position: 20, importance: #HIGH } ]
key exidv as Hu,
....
here is the XML view
<mvc:View
controllerName="ns.shipment1.controller.Worklist"
xmlns="sap.m"
xmlns:mvc="sap.ui.core.mvc"
xmlns:semantic="sap.f.semantic"
xmlns:smartFilterBar="sap.ui.comp.smartfilterbar"
xmlns:app="http://schemas.sap.com/sapui5/extension/sap.ui.core.CustomData/1"
xmlns:smartTable="sap.ui.comp.smarttable">
<semantic:SemanticPage
id="page"
headerPinnable="false"
toggleHeaderOnTitleClick="false">
<semantic:titleHeading>
<Title
text="{i18n>worklistTitle}"
level="H2"/>
</semantic:titleHeading>
<semantic:content>
<!-- use this to make the table occupy the available screen height -->
<VBox fitContainer="true">
<!-- FILTER BAR ******************************************** -->
<smartFilterBar:SmartFilterBar
id="smartFilterBar"
entitySet="ZTESTV_CDS_SHP"
persistencyKey="SmartFilter_Explored"
basicSearchFieldName="Shipment"
enableBasicSearch="true"
visible="true"
considerSelectionVariants="true"
showFilterConfiguration="true">
</smartFilterBar:SmartFilterBar>
<!-- SMART TABLE ******************************************** -->
<smartTable:SmartTable
id="ShipmentTable"
entitySet="ZTESTV_CDS_SHP"
smartFilterId="smartFilterBar"
tableType="Table"
useExportToExcel="true"
beforeExport="onBeforeExport"
useVariantManagement="true"
useTablePersonalisation="true"
header="Shipment Items"
showRowCount="true"
persistencyKey="SmartTableAnalytical_Explored"
enableAutoBinding="true"
class="sapUiResponsiveContentPadding"
editTogglable="false"
app:useSmartField="true"
app:useSmartToggle="true">
</smartTable:SmartTable>
</VBox>
Actually, I found the Annotation model in /IWFND/MAINT_SERVICE transaction, by selecting the service, then service implemetation button and annotation model button.
I have added the annotations property in settings with the reference to the array which contains the annotation model. Note that in my case, annotation model is ZTESTV_CDS_SHP_CDS_VAN, when it usually ends by ANNO_MDL.
{
"dataSources": {
"mainService": {
"uri": "/sap/opu/odata/sap/ZTESTV_CDS_SHP_CDS/",
"type": "OData",
"settings": {
"odataVersion": "2.0",
"annotations": [
"ZTESTV_CDS_SHP_CDS_ANNOTATION"
],
"localUri": "localService/metadata.xml"
}
},
"ZTESTV_CDS_SHP_CDS_ANNOTATION": {
"uri": "/sap/opu/odata/IWFND/CATALOGSERVICE;v=2/Annotations(TechnicalName='ZTESTV_CDS_SHP_CDS_VAN',Version='0001')/$value/",
"type": "ODataAnnotation"
}
}
}
Screenshot of the manifest:

sapui5 Not able to display data in detail page

I have a problem to display data in my detail page. I've tried almost everything but its dosnt work. On main page everything looks fine. Routing work (display proper ID on network address).
Details.controller.js :
return Controller.extend("sapProject.controller.Details", {
onInit: function () {
var oTable = this.getView().byId("details");
var oModel = new sap.ui.model.json.JSONModel();
oModel.loadData("model/Object.json");
oTable.setModel(oModel);
var oRouter = sap.ui.core.UIComponent.getRouterFor(this);
oRouter.getRoute("Details").attachMatched(this._onRouteMatched, this);
},
_onRouteMatched : function (oEvent) {
var oArgs, oView;
oArgs = oEvent.getParameter("arguments");
oView = this.getView();
oView.bindElement({
path : "/Objects(" + oArgs.employeeId + ")",
events : {
dataRequested: function () {
oView.setBusy(true);
},
dataReceived: function () {
oView.setBusy(false);
}
}
});
},
and this is my Details.view.xml:
<Page
id="details"
title="{i18n>EmployeeDetailsOf} {FirstName} {LastName}"
showNavButton="true"
navButtonPress="onBack"
class="sapUiResponsiveContentPadding">
<content>
<Panel
width="auto"
class="sapUiResponsiveMargin sapUiNoContentPadding">
<headerToolbar >
<Toolbar>
<Title text="{i18n>EmployeeIDColon} {EmployeeID}" level="H2"/>
<ToolbarSpacer />
</Toolbar>
</headerToolbar>
<content>
<f:SimpleForm>
<f:content>
<Label text="{i18n>FirstName}" />
<Text text="{FirstName}" />
<Label text="{i18n>LastName}" />
</f:content>
</f:SimpleForm>
</content>
</Panel>
</content>
</Page>
I think you are binding an empty model to your detail view because probably the loadData function is not completed when you set the model on the Table.
Try to load your json file in the manifest (best option) or differ the setModel on the _onRouteMatched function (although I don't see any table in your detail view).
EDIT:
You can also use this code after oModel.loadData("model/Object.json");
oModel.attachEventOnce("requestCompleted", function(oEvent) {
// Here your file is fully loaded
});
Firstly I recommend you to bind like this:
var sObjectPath = this.getModel().createKey("Objects", {
ID: oArgs.employeeId
});
this._bindView("/" + sObjectPath);
...
}
_bindView: function (sObjectPath) {
//Todo: Set busy indicator during view binding
this.getView().bindElement({
path: sObjectPath,
parameters: {
},
events: {
change: this._onBindingChange.bind(this),
dataRequested: function () {
}.bind(this),
dataReceived: function () {
}.bind(this)
}
});
},
Secondly check if oArgs.employeeId has a valid value and also if the model is loaded with data, easily set a brekapoint or write console.log(this.getView().getModel().oData).

Data binding issue with sap.m.SelectDialog

I'm using Sap.m.SelectDialog to display the value request(F4 help in abap).When i do it with JS view all is good,but when do it with XML view by creating the fragment, binding is not happening with the "items" aggregation.
please let me know what went wrong.
var mydata = { data : [
{
info: "SAP UI5",
name: "Sam",
},
{
info: "SAP UI5",
name: "Ram",
},
{
info: "SAP UI5",
name: "Prem",
}
]};
Js view logic:
var oDialog = new sap.m.SelectDialog({
title: "Select an item",
items: {
path:"/data",
template : new sap.m.StandardListItem({
title: "{name}"
})
}
})
oDialog.open();
}
XML fragment :
<SelectDialog xmlns="sap.m"
id ="id3"
title="Select a product">
<items id="ls3"
path="/data">
<StandardListItem title="{name}">
</StandardListItem>
</items>
.
Reslut of JS view
Result of Xml view
Try XML fragment this way:
<SelectDialog xmlns="sap.m"
id ="id3"
items="{/data}"
title="Select a product">
<items>
<StandardListItem title="{name}"/>
</items>
</SelectDialog>

Empty list data binding

I want set the content of a list into a popover.
The result is this:
There are two list by different data binding. The 2nd work and the 1st not work...
This is the xml of the popover
<Popover
showHeader="false"
contentWidth="320px"
contentHeight="500px"
placement="Bottom" >
<List
items="{menuPath>/pathlist}">
<StandardListItem title="{level}" />
</List>
<List
items="{/nodes}">
<StandardListItem
title="{text}"
type="Navigation"
tap="doNavOnSelect" >
</StandardListItem>
</List>
</Popover>
The 1st data-binding (not-work) is this:
var aPath=new Array();
obj=new Object(); obj.level='lev1'; aPath.push(obj);
obj=new Object(); obj.level='lev2'; aPath.push(obj);
obj=new Object(); obj.level='lev3'; aPath.push(obj);
var oModel = new sap.ui.model.json.JSONModel();
//oModel.setData({pathlist:aPath}, true);
oModel.setData({pathlist:[{level:'uno'},{level:'due'},{level:'tre'}]}, true);
sap.ui.getCore().setModel(oModel, "menuPath");
and the 2nd data-binding (work) is this:
this.getView().setModel(new sap.ui.model.json.JSONModel("apps/appIntra/master/GEN_intra_Master.json"));
and the json file is this:
{
"nodes" : [
{
"id" : "help",
"text" : "Help"
},
{
"id" : "intra_acquisti",
"text" : "ACQUISTI"
},
{
"id" : "intra_cessioni",
"text" : "CESSIONI"
}
]
}
Instead of
<StandardListItem title="{level}" />
use
<StandardListItem title="{menuPath>level}" />
If you use named models, always remember to include them in all the bindings where necessary :)