I am trying to show the data of a particular item in a list when ,clicked upon , on the next page (view)
Here Overview.view.xml is the default view with a clickable list connected to an oData model.
Next is the controller for Overview navigating to the next page i.e. Overview.controller.js.
The next page is Detail.view.xml
I want to show details of clicked item in this page.
#Overview.view.xml
<mvc:View controllerName="root.demo.controller.Overview" xmlns:html="http://www.w3.org/1999/xhtml" xmlns:mvc="sap.ui.core.mvc"
displayBlock="true" xmlns="sap.m">
<App >
<pages>
<Page title="{i18n>title}">
<content>
<List headerText="list" class="sapUiResponsiveMargin" width="auto" items="{HANA>/person}">
<items>
<ObjectListItem title="{HANA>ID} x {HANA>FIRSTNAME}" type="Navigation" press="onPress"/>
</items>
</List>
</content>
</Page>
</pages>
</App>
</mvc:View>
#Overview.controller.js
sap.ui.define([
"sap/ui/core/mvc/Controller"
], function (Controller) {
"use strict";
return Controller.extend("root.demo.controller.App", {
onPress: function (oEvent) {
var oRouter = sap.ui.core.UIComponent.getRouterFor(this);
oRouter.navTo("detail");
}
});
});
#Detail.view.xml
<mvc:View xmlns="sap.m"
xmlns:mvc="sap.ui.core.mvc">
<Page title="{i18n>detailPageTitle}">
<ObjectStatus title="PAGE 1"
/>
</Page>
</mvc:View>
If you have different Entity Sets with association you need to send the key of the association to the second view and there create the binding towards the assocaited entity set
If not you need to send the object to the second view
Either way you need to navigate with parameters
In the manifest file you need to specify the routing
"routes": [
{
"name": "TargetMaster",
"pattern": "RouteMaster",
"target": [
"TargetMaster"
]
},
{
"pattern": "Detail/{storePath}",
"name": "Detail",
"target": "Detail"
}
],
"targets": {
"TargetMaster": {
"viewType": "XML",
"transition": "slide",
"clearControlAggregation": false,
"viewName": "Master"
},
"Detail": {
"viewType": "XML",
"viewName": "Detail"
}
}
In the Overview Controller you need to create the navigation similarly to
onListItemPress: function(oEvent){
var oItem = oEvent.getSource();
var oRouter = sap.ui.core.UIComponent.getRouterFor(this);
oRouter.navTo("Detail",{
storePath: oItem.getBindingContext().getProperty("Store")
});
}
you can find more information on the official documentation here
Related
<mvc:View xmlns:mvc="sap.ui.core.mvc"
xmlns="sap.m"
xmlns:core="sap.ui.core"
controllerName="z.controller.Main">
<Page id="page" title="ComboBox" >
<content>
<ComboBox name="Drop-down List" id="box0" items="{/country}">
<items >
<core:Item key="{Key}" text="{Name}" id="item0"/>
</items>
</ComboBox>
</content>
<Button text="Change" press="onChange"/>
</Page>
</mvc:View>
model1.json
{
"country": [{
"Key": "IN",
"Name": "India"
},
{
"Key": "US",
"Name": "USA"
},{
"Key": "UK",
"Name": "United Kingdom"
}]
}
model2.json
{
"country2": [{
"Key": "BD",
"Name": "Bangladesh"
},
{
"Key": "CA",
"Name": "Canada"
},{
"Key": "FR",
"Name": "France"
}]
}
Main.controller.js
sap.ui.define([
'sap/ui/core/mvc/Controller',
"sap/ui/model/json/JSONModel",
"z/models/model"
], function(Controller,JSONModel, localModel) {
'use strict';
return Controller.extend("z.controller.Main",{
onInit: function(){
var oModel = localModel.createJSONModel("models/data/model1.json");
sap.ui.getCore().setModel(oModel);
var oModel2 = localModel.createJSONModel("models/data/model2.json");
sap.ui.getCore().setModel(oModel2, "model2");
},
onChange: function(){
}
})
});
controller.js
sap.ui.define([
'sap/ui/core/mvc/Controller',
"sap/ui/model/json/JSONModel"
], function(Controller,JSONModel) {
'use strict';
return {
createJSONModel: function(filePath){
var oModel = new JSONModel();
oModel.loadData(filePath);
return oModel;
}
}
});
I have two JSON models and building a combo list using aggregation binding(items="{/country}") by reading data from model1. I am trying to fill the same Combolist by reading the data from the model2 on a button press event.
You can switch the model by using it as a prefix model2> (as you have defined in the Main.controller.js in the onInit method) in the binding path:
onChange: function() {
var oComboBox = this.getView().byId("box0");
oComboBox.bindItems("model2>/country2", {
template: this.getView().byId("item0")
});
}
And change the aggregation from items to dependents.
<ComboBox name="Drop-down List" id="box0" items="{/country}">
<dependents>
<core:Item key="{Key}" text="{Name}" id="item0"/>
</dependents>
</ComboBox>
I currently try to learn UI5 and right now the concept of routing. My current use case is, that the user selects one radio button out of a group and then presses a button. On my second view it should show the selected radio button.
I've set up both views, the routes and the targets. But it somehow does not want to load the View. If I have a look at the URL it enters the pattern of the route into it but it does not load the view - is there anything I need to do?
The rounter is initialized in the component.js
After I clicked the button the following method gets called:
this.getOwnerComponent().getRouter().navTo("overview");
this is my routing config:
"flexEnabled": false,
"rootView": {
"viewName": "com.enh.ess.com.enh.ess.view.Booking",
"type": "XML",
"async": true,
"id": "Booking"
},
// some stuff in between
"routing": {
"config": {
"routerClass": "sap.m.routing.Router",
"viewType": "XML",
"async": true,
"viewPath": "com.ess.view",
"controlAggregation": "pages",
"controlId": "app",
"clearControlAggregation": false,
"bypassed": {
"target": "noFound"
}
},
"routes": [
{
"name": "home",
"pattern": "",
"target": "booking_tar"
},
{
"name": "overview",
"pattern": "overviewBooking",
"target": "Overview"
}
],
"targets": {
"booking_tar": {
"viewType": "XML",
"transition": "slide",
"viewId": "Booking",
"viewName": "Booking"
},
"Overview": {
"viewType": "XML",
"viewName": "Overview"
},
"notFound": {
"viewId": "notFound",
"viewType": "XML",
"viewName": "NotFound",
"transition": "show"
}
}
}
my rootView ( Booking.view.xml ) is built like this ( I've removed some stuff here, like the attributes for the buttons or the path of the contrllerName - and I added one "comment" for the button ):
<mvc:View controllerName="" xmlns:mvc="sap.ui.core.mvc" displayBlock="true" xmlns="sap.m" xmlns:layout="sap.ui.layout">
<Shell id="shell">
<App id="app">
<pages>
<Page id="page" title="{i18n>title}">
<content>
<layout:VerticalLayout>
<RadioButtonGroup id="" columns="1"/>
<layout:HorizontalLayout>
<Button /> <-- when this button gets clicked it should load the new view
<Button />
</layout:HorizontalLayout>
</layout:VerticalLayout>
</content>
</Page>
</pages>
</App>
</Shell>
</mvc:View>
in my view Booking.view.xml I have the button. After I click it, it should navigate to the overview target / the Overview.viewl.xml - and as I said, it writes the value into the URL, but it doesn't load the view.
Do you have any idea what I also need to do? I've tried some things ( like view levels, that didn't work )
I am currently working in the WebIDE - if this is relevant for this.
thank you!
I suggest you to use a different strategy for the XML "encapsulation" to better exploit the routing mechanism: create an (almost) empty root view, such as App.view.xml, as follows:
<mvc:View xmlns:mvc="sap.ui.core.mvc" xmlns="sap.m" displayBlock="true">
<App id="idAppControl">
<pages>
<!-- Routed views are added here -->
</pages>
</App>
</mvc:View>
Modify your manifest accordingly
In /sap.ui5/rootView:
{
"viewName": "your.namespace.view.App",
"type": "XML",
"async": true
},
and in /sap.ui5/routing/config:
{
"routerClass": "sap.m.routing.Router",
"viewType": "XML",
"async": true,
"viewPath": "your.namespace.view",
"controlAggregation": "pages",
"controlId": "idAppControl"
},
Please note that the controlId and the ID of the <App> must be the same.
Now you've prepared the "container" for your routes and your Views can be simplified as follows:
<mvc:View controllerName="your.namespace.controller.Booking"
xmlns="sap.m"
xmlns:mvc="sap.ui.core.mvc">
<Page title="title" class="sapUiResponsiveContentPadding">
<content>
<!-- Your content here -->
</content>
</Page>
</mvc:View>
Same structure also for your detail page. Please remember that your Home page should have an empty routing pattern ("pattern" : "") in order to be the first hit route.
To learn more, take a look at the tutorial Navigation and Routing.
I am writing a simple application which aims to display the local data of a json file.
How can I sum the values from a column?
Expected effect:
enter image description here
Below are the files to recreate the case
V_Root.view.xml
<mvc:View controllerName="Nawigacja.ZNavigation.controller.V_Root" xmlns:mvc="sap.ui.core.mvc" displayBlock="true" xmlns="sap.m">
<App id="V_Main">
<pages>
<Page title="Root View">
<content></content>
</Page>
</pages>
</App>
</mvc:View>
V_Source.view.xml
<mvc:View xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc" xmlns="sap.m" controllerName="Nawigacja.ZNavigation.controller.V_Source"
xmlns:html="http://www.w3.org/1999/xhtml">
<App>
<pages>
<Page title="Soruce View">
<content>
<VBox width="100%" direction="Column" id="__vbox0">
<items>
<Button text="Button 1" width="100px" id="__button2" press="GoToTarget_1"/>
<Button text="Button 2" width="100px" id="__button3" press="GoToTarget_2"/>
</items>
</VBox>
</content>
</Page>
</pages>
</App>
</mvc:View>
V_Target_1.view.xml
<mvc:View xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc" xmlns="sap.m" controllerName="Nawigacja.ZNavigation.controller.V_Target_1"
xmlns:html="http://www.w3.org/1999/xhtml">
<App>
<pages>
<Page title="Target One" showNavButton="true" navButtonPress="GoOneScreenBack">
<content>
<ScrollContainer vertical="true" focusable="true" height="95%">
<Table id="namiot" items="{path: '/namiot'}">
<columns>
<Column width="12rem">
<Label text="Najem"/>
</Column>
<Column minScreenWidth="tablet" demandPopin="true">
<Label text="Price"/>
</Column>
<Column width="12rem">
<Label text="Total Cost"/>
<footer>
<Text text="Sum:"/>
</footer>
</Column>
</columns>
<ColumnListItem>
<Text text="{ProductType}"></Text>
<Text text="{ProductPrice}"></Text>
<Text text="{ProductTotal}"></Text>
</ColumnListItem>
</Table>
</ScrollContainer>
</content>
</Page>
</pages>
</App>
</mvc:View>
V_Root.controller.js
sap.ui.define([
"sap/ui/core/mvc/Controller"
], function (Controller) {
"use strict";
return Controller.extend("Nawigacja.ZNavigation.controller.V_Root", {
onInit: function () {
}
});
});
V_Source.controller.js
sap.ui.define([
"sap/ui/core/mvc/Controller"
], function (Controller) {
"use strict";
return Controller.extend("Nawigacja.ZNavigation.controller.V_Source", {
/**
* Called when a controller is instantiated and its View controls (if available) are already created.
* Can be used to modify the View before it is displayed, to bind event handlers and do other one-time initialization.
* #memberOf Nawigacja.ZNavigation.view.V_Source
*/
onInit: function () {
},
GoToTarget_1: function () {
// Now Get the Router Info
var oRouter = sap.ui.core.UIComponent.getRouterFor(this);
// Tell the Router to Navigate To Route_Tar_1
oRouter.navTo("Route_Tar_1", {});
},
GoToTarget_2: function () {
// Now Get the Router Info
var oRouter = sap.ui.core.UIComponent.getRouterFor(this);
// Tell the Router to Navigate To Route_Tar_2
oRouter.navTo("Route_Tar_2", {});
}
/**
* Similar to onAfterRendering, but this hook is invoked before the controller's View is re-rendered
* (NOT before the first rendering! onInit() is used for that one!).
* #memberOf Nawigacja.ZNavigation.view.V_Source
*/
// onBeforeRendering: function() {
//
// },
/**
* Called when the View has been rendered (so its HTML is part of the document). Post-rendering manipulations of the HTML could be done here.
* This hook is the same one that SAPUI5 controls get after being rendered.
* #memberOf Nawigacja.ZNavigation.view.V_Source
*/
// onAfterRendering: function() {
//
// },
/**
* Called when the Controller is destroyed. Use this one to free resources and finalize activities.
* #memberOf Nawigacja.ZNavigation.view.V_Source
*/
// onExit: function() {
//
// }
});
});
V_Target_1.controller.js
sap.ui.define([
"sap/ui/core/mvc/Controller",
"sap/ui/core/routing/History",
"Nawigacja/ZNavigation/formatter/Formatter"
], function (Controller, History,formatter) {
"use strict";
return Controller.extend("Nawigacja.ZNavigation.controller.V_Target_1", {
/**
* Called when a controller is instantiated and its View controls (if available) are already created.
* Can be used to modify the View before it is displayed, to bind event handlers and do other one-time initialization.
* #memberOf Nawigacja.ZNavigation.view.V_Target_1
*/
onInit: function () {
var oTable = this.getView().byId("namiot");
var oModel = new sap.ui.model.json.JSONModel();
oModel.loadData("model/namiot.json");
oTable.setModel(oModel);
},
GoOneScreenBack: function (Evt) {
var oHistory = History.getInstance();
var sPreviousHash = oHistory.getPreviousHash();
// Go one screen back if you find a Hash
if (sPreviousHash !== undefined) {
window.history.go(-1);
}
// If you do not find a correct Hash, go to the Source screen using default router;
else {
var oRouter = sap.ui.core.UIComponent.getRouterFor(this);
oRouter.navTo("", true);
}
},
formatter: formatter
/**
* Similar to onAfterRendering, but this hook is invoked before the controller's View is re-rendered
* (NOT before the first rendering! onInit() is used for that one!).
* #memberOf Nawigacja.ZNavigation.view.V_Target_1
*/
// onBeforeRendering: function() {
//
// },
/**
* Called when the View has been rendered (so its HTML is part of the document). Post-rendering manipulations of the HTML could be done here.
* This hook is the same one that SAPUI5 controls get after being rendered.
* #memberOf Nawigacja.ZNavigation.view.V_Target_1
*/
// onAfterRendering: function() {
//
// },
/**
* Called when the Controller is destroyed. Use this one to free resources and finalize activities.
* #memberOf Nawigacja.ZNavigation.view.V_Target_1
*/
// onExit: function() {
//
// }
});
});
models.js
sap.ui.define([
"sap/ui/model/json/JSONModel",
"sap/ui/Device"
], function (JSONModel, Device) {
"use strict";
return {
createDeviceModel: function () {
var oModel = new JSONModel(Device);
oModel.setDefaultBindingMode("OneWay");
return oModel;
}
};
});
manifest.json
{
"_version": "1.12.0",
"sap.app": {
"id": "Nawigacja.ZNavigation",
"type": "application",
"i18n": "i18n/i18n.properties",
"applicationVersion": {
"version": "1.0.0"
},
"title": "{{appTitle}}",
"description": "{{appDescription}}",
"sourceTemplate": {
"id": "ui5template.basicSAPUI5ApplicationProject",
"version": "1.40.12"
}
},
"sap.ui": {
"technology": "UI5",
"icons": {
"icon": "",
"favIcon": "",
"phone": "",
"phone#2": "",
"tablet": "",
"tablet#2": ""
},
"deviceTypes": {
"desktop": true,
"tablet": true,
"phone": true
}
},
"sap.ui5": {
"flexEnabled": false,
"rootView": {
"viewName": "Nawigacja.ZNavigation.view.V_Root",
"type": "XML",
"async": true,
"id": "V_Root"
},
"dependencies": {
"minUI5Version": "1.65.6",
"libs": {
"sap.ui.layout": {},
"sap.ui.core": {},
"sap.m": {}
}
},
"contentDensities": {
"compact": true,
"cozy": true
},
"models": {
"i18n": {
"type": "sap.ui.model.resource.ResourceModel",
"settings": {
"bundleName": "Nawigacja.ZNavigation.i18n.i18n"
}
}
},
"resources": {
"css": [{
"uri": "css/style.css"
}]
},
"routing": {
"config": {
"routerClass": "sap.m.routing.Router",
"viewType": "XML",
"async": true,
"viewPath": "Nawigacja.ZNavigation.view",
"controlAggregation": "pages",
"controlId": "V_Main",
"clearControlAggregation": false,
"viewLevel": 1
},
"routes": [{
"name": "Route_Source",
"pattern": "",
"target": ["Target_Source"],
"titleTarget": ""
}, {
"name": "Route_Tar_1",
"pattern": "V_Target_1",
"titleTarget": "",
"greedy": false,
"target": ["Target_1"]
}, {
"name": "Route_Tar_2",
"pattern": "V_Target_2",
"titleTarget": "",
"greedy": false,
"target": ["Target_2"]
}],
"targets": {
"Target_1": {
"viewType": "XML",
"transition": "slide",
"clearAggregation": true,
"viewName": "V_Target_1",
"viewLevel": 2
},
"Target_2": {
"viewType": "XML",
"transition": "slide",
"clearAggregation":"true",
"viewName": "V_Target_2",
"viewLevel": 2
},
"Target_Source": {
"viewType": "XML",
"clearAggregation":"true",
"viewName": "V_Source",
"viewLevel": 1
}
}
}
}
}
namiot.json
{
"namiot":[
{
"ProductName": "Product1",
"ProductType": "Type1",
"ProductPrice": "25",
"ProductTotal": "5000",
"Productadd": "",
"ProductaddPr":""
},
{
"ProductName": "Product2",
"ProductType": "Type2",
"ProductPrice": "25",
"ProductTotal": "5000",
"Productadd": "",
"ProductaddPr":""
}
]
}
there are probably x options to realize this.
You could use the method attachUpdateFinished which will be called when the Tablebinding get's updated (the table receives the Items). Then you can summarize the values and store it in an JSONModel and bind it to the footertext. When the binding (the items) change the sum would be updated.
oTable.attachUpdateFinished(function (oEvt) {
var iSum = 0;
var aItems = oEvt.getSource().getItems();
for (var i = 0; i < aItems.length; i++) {
var oItem = aItems[i].getBindingContext().getObject();
iSum = iSum + parseFloat(oItem.ProductTotal);
}
//Do whatever you want with the iSum
});
Here's an example how it could be realized.
Code Sample
I would like to use Classification component in my ui5 app.
The structure of the component looks as following:
I would like to pickup the classification component. The content of the Component-dbg.js looks as following:
sap.ui.define([
"sap/ui/core/UIComponent",
"sap/suite/ui/generic/template/extensionAPI/ReuseComponentSupport",
"sap/suite/ui/generic/template/extensionAPI/UIMode",
"sap/i2d/lo/lib/vchclf/common/Constants",
"sap/i2d/lo/lib/vchclf/components/classification/service/ClassificationService"
], function(UIComponent, ReuseComponentSupport, UIMode, Constants, ClassificationService) {
"use strict";
/**
* Classification Component.
* #class ClassificationComponent
* #extends sap.ui.core.UIComponent
*/
return UIComponent.extend("sap.i2d.lo.lib.vchclf.components.classification.Component", {
metadata: {
manifest: "json",
properties: {
uiMode: {
type: "string",
group: "standard",
defaultValue: "Display"
I would like to use it in my app and tried to bind in manifest file as following:
"dependencies": {
"minUI5Version": "1.30.0",
"libs": {
"sap.ui.layout": {},
"sap.ui.core": {},
"sap.m": {}
},
"components": {
"sap.i2d.lo.lib.vchclf.components.classification": {}
}
},
"componentUsages": {
"classcomponent": {
"name": "sap.i2d.lo.lib.vchclf.components.classification"
}
},
and I've got the following error:
Uncaught Error: failed to load 'sap/i2d/lo/lib/vchclf/components/classification/Component.js' from ../../resources/sap/i2d/lo/lib/vchclf/components/classification/Component.js: 404 - Not Found
What am I doing wrong?
Update
I also tried:
<mvc:View controllerName="ch.mindustrie.CLASSIFICATION.controller.App" xmlns:html="http://www.w3.org/1999/xhtml" xmlns:mvc="sap.ui.core.mvc"
displayBlock="true" xmlns="sap.m" xmlns:core="sap.ui.core">
<App id="idAppControl">
<pages>
<Page title="{i18n>title}">
<content>
<core:ComponentContainer id="classificationComponentContainer" name="sap.i2d.lo.lib.vchclf.components.classification" propagateModel="true"/>
</content>
</Page>
</pages>
</App>
</mvc:View>
and also got error message:
I have the following data in my model:
{
vertexTable: [
{
"NAME": "Tethys",
"TYPE":"titan",
"RESIDENCE":"Othrys"
},
{
"NAME": "Oceanus",
"TYPE": "titan",
"RESIDENCE": "Othrys"
}
],
vertexAttributes: [
{
"COLUMN_NAME": "NAME",
"DATA_TYPE_NAME": "VARCHAR"
},
{
"COLUMN_NAME": "TYPE",
"DATA_TYPE_NAME": "VARCHAR"
},
{
"COLUMN_NAME": "RESIDENCE",
"DATA_TYPE_NAME": "VARCHAR"
}
]
}
I want to display this data in my view such that there is a label coming from vertexAttributes/COLUMN_NAME and each label has an associated dropdown / select box coming from ..
vertexTable/NAME for the NAME label,
vertexTable/TYPE for the TYPE label, and
vertexTable/RESIDENCE for the RESIDENCE label.
I thought about using a Form control which has aggregation binding to formElements="{/vertexattributes}" and then each Form Element bound to "{COLUMN_NAME}" from vertexAttributes. But now, I want to put the Select control which has an aggregation binding to vertexTable and then the items bound to NAME, TYPE, and RESIDENCE.
Below is the code I tried in my view:
<f:form>
<f:FormContainer formElements="{/vertexAttributes}">
<f:FormElement label="{COLUMN_NAME}">
<List id="values" items="{path: 'VALUES', templateShareable: false}">
<StandardListItem title="{value}"></StandardListItem>
</List>
</f:FormElement>
</f:FormContainer>
</f:form>
I had to use templateShareable because I was getting an error. Not completely sure what it is.
Also, instead of select / dropdown, I am using a List to show the complete values.
Is this the right way to do it or is there a better way?
I came across factory function but I am unable to implement it.
Here is a working example:
sap.ui.getCore().attachInit(() => sap.ui.require([
"sap/ui/model/json/JSONModel",
"sap/ui/layout/form/FormElement",
"sap/m/Label",
"sap/m/Select",
"sap/ui/core/Item",
], (JSONModel, FormElement, Label, Select, Item) => sap.ui.xmlview({
viewContent: `<mvc:View
xmlns:mvc="sap.ui.core.mvc"
xmlns:form="sap.ui.layout.form"
xmlns="sap.m"
controllerName="demo.MyController"
>
<form:Form editable="true">
<form:layout>
<form:ResponsiveGridLayout/>
</form:layout>
<form:FormContainer
formElements="{
path: '/vertexAttributes',
factory: '.createFormElement'
}"
/>
</form:Form>
</mvc:View>`,
controller: sap.ui.controller("demo.MyController", {
createFormElement: function(id, context) {
const columnName = context.getProperty("COLUMN_NAME");
return new FormElement(id).setLabel(new Label({
text: columnName,
})).addField(new Select().bindItems({
path: "/vertexTable",
template: new Item().bindProperty("text", columnName),
}));
},
}),
}).setModel(new JSONModel({
vertexTable: [{
"NAME": "Tethys",
"TYPE": "Titan1",
"RESIDENCE": "Othrys1"
},
{
"NAME": "Oceanus",
"TYPE": "Titan2",
"RESIDENCE": "Othrys2"
},
],
vertexAttributes: [{
"COLUMN_NAME": "NAME",
"DATA_TYPE_NAME": "VARCHAR"
},
{
"COLUMN_NAME": "TYPE",
"DATA_TYPE_NAME": "VARCHAR"
},
{
"COLUMN_NAME": "RESIDENCE",
"DATA_TYPE_NAME": "VARCHAR"
},
]
})).placeAt("content")));
<script src="https://openui5.hana.ondemand.com/resources/sap-ui-core.js" id="sap-ui-bootstrap"
data-sap-ui-libs="sap.ui.layout, sap.m, sap.ui.core"
data-sap-ui-preload="async"
data-sap-ui-theme="sap_belize"
data-sap-ui-compatVersion="edge"
data-sap-ui-resourceRoots='{"demo": "./"}'
data-sap-ui-xx-waitForTheme="true"></script>
<body id="content" class="sapUiBody sapUiSizeCompact"></body>
The design of your data structure is somewhat questionable. The fact that the value (of vertexAttributes/COLUMN_NAME) is the key (of vertexTable/*) in other objects makes the implementation complicated. Nevertheless, as you've already tried before, displaying the appropriate data is still possible with a factory function.
The example above creates a Select control in each iteration of the createFormElement call. Then, the select item can bind its text with the current columnName as a path.
About the templateShareable: https://stackoverflow.com/a/47734086/5846045