How to build an expandable sap.m.Table in sapui5? - sapui5

I am searching for a kind of TreeTable that uses sap.m.Table as base.
My first "hack" looks like this:
Experimental data model:
var oModel = new sap.ui.model.json.JSONModel({
"Items" : [
{"Name" : "A", "SubItems" : [
{"Name" : "A.1" },
{"Name" : "A.2" },
{"Name" : "A.3" },
]
},
{"Name" : "B", "SubItems" : [
{"Name" : "B.1" }
]
},
]
});
this.getView().setModel(oModel, "expand");
Experimental Table implementation:
var oContent = new sap.m.Table({
items : {
path : "expand>/Items",
template : new sap.m.ColumnListItem({
customData : [ new sap.ui.core.CustomData({
key : "SubItems",
value : "SubItems",
customData : {
path : "expand>SubItems",
template : new sap.ui.core.CustomData({
key : this.createId("subItem"),
value : new sap.m.ColumnListItem({
cells : [
new sap.m.Text({
text: "{expand>Name}",
})
]
})
})
}
})
],
type : sap.m.ListType.Active,
cells: [
new sap.m.Text({ text: "{expand>Name}" }),
],
press : [function(oEvent) {
var oRow = oEvent.getSource();
var oTable = oRow.getParent();
var oItems = oTable.getItems();
var insertIndex = -1;
var oSubItemsData = undefined;
for (var i=0;i<oItems.length;i++) {
if (oItems[i]==oRow) {
oSubItemsData = oRow.getAggregation("customData").filter(function(oData) {return oData.getProperty("key") == "SubItems";});
insertIndex = i;
}
}
var oSubItems = oSubItemsData[0].getAggregation("customData").map(function(oData) {return oData.getValue();});
for (var j=0;j<oSubItems.length;j++) {
var mShownSubItems = oItems.filter(function(oShownItem) {
return oShownItem == oSubItems[j];
});
if (mShownSubItems.length>0) {
console.log("removing"+j);
oTable = oTable.removeItem(oSubItems[j]);
} else {
console.log("adding "+(insertIndex+j+1));
oTable = oTable.insertItem(oSubItems[j],insertIndex+j+1);
}
}
}, oController]
})
},
columns : [ new sap.m.Column({}) ],
});
I figured out different problems with this "hack".
First of all the binding of the SubItems is not displayed, if I use hard coded text the text is shown.
Second problem is, that I can only insert exactly one row.
How can this be solved?

You may be interested in the Table - Breadcrumb sample in Explored. It uses sap.m.Table as a base and can display a hierarchy of data, in a tree table kind of style.

I have bumped into the same issue and I've solved it by using a sap.m.Panel as a sap.m.CustomListItem aggregation of the sap.m.List. If you wish to expand it by clicking anywhere on the row (collapsed Panel) and not only on the Panel's expand Button, you could get the aggregation go trough a factory, which can do something like this
var oUIControl = this.byId("custItem").clone(sId);
var oPanel = oUIControl.getContent()[0];
oPanel.addEventDelegate({
onclick: function (e) {
try {
if (sap.ui.getCore().byId(e.target.id).getMetadata().getElementName() !== "sap.ui.core.Icon") {
oPanel.setExpanded(!oPanel.getExpanded());
}
} catch (e) {
oPanel.setExpanded(!oPanel.getExpanded());
}
}
});
return oUIControl;
The check is needed because without it the click event is fired twice when clicking on the expand button itself. With it we trigger custom click event when the user clicks anywhere else on the panel row.

Related

SAPUI5 formatter parameter value is always null

I am trying to add an icon to my table column. The icon should be selected depending on the value. Therefore I implemented some formatter function which is based in the model/formatter.js file.
Here is the code I try to add the the table column:
new sap.ui.layout.VerticalLayout({
content: [
new sap.m.Label({text:"{Items>Status}"}),
new sap.ui.core.Icon({
src: {
parts: [
"Items>Status"
],
formatter: Formatter.formatStatusIcon
},
size: "1rem",
color: {
parts: [
"Items>Status"
],
formatter: Formatter.formatStatusIconColor
}
})
]
})
The label does display the correct value. The icon is not displayed. The formatter function has as input value always null even though the values exist and are not null. I am using SAPUI5 version 1.61.2. I already tried different syntaxes of the parts property but none of them did work. I also tried adding some static value instead of "Items>Status" for testing purpose but the input in the formatter function is still null.
Has anyone an idea why the input of the formatter function is always null?
Based on the your input, I have understood that you have a JS view and your are changing the Icon and its color based on the status
View.js
var oTable = new sap.m.Table("idPrdList", {
headerText : "List of Products",
headerDesign : sap.m.ListHeaderDesign.Standard,
mode : sap.m.ListMode.None,
includeItemInSelection : false,
});
var col1 = new sap.m.Column({header: new sap.m.Label({text:"Product Name"})});
oTable.addColumn(col1);
var col2 = new sap.m.Column({header: new sap.m.Label({text:"Description"})});
oTable.addColumn(col2);
var col3 = new sap.m.Column({header: new sap.m.Label({text:"Price"})});
oTable.addColumn(col3);
controller.js
var oModel = new sap.ui.model.json.JSONModel();
oModel.setData({
'items': [
{
'ProductID': "sdf",
'ProductName': "asdf",
"Status": "1"
},
{
'ProductID': "ss",
'ProductName': "asf",
"Status": "1"
},
{
'ProductID': "fff",
'ProductName': "asdf",
"Status": "2"
},
{
'ProductID': "fas",
'ProductName': "asdf",
"Status": "1"
},
{
'ProductID': "asdfa",
'ProductName': "asdfwer",
"Status": "2"
}]
});
sap.ui.getCore().setModel(oModel, "tableData");
var oTable = sap.ui.getCore().byId("idPrdList");
var colItems = new sap.m.ColumnListItem("colItems", {
type: "Active"
});
var txtNAME = new sap.m.Text({
text: "{tableData>ProductID}"
});
colItems.addCell(txtNAME);
var txtNAME2 = new sap.m.Text({
text: "{tableData>ProductName}"
});
colItems.addCell(txtNAME2);
var txtNAME3 = new sap.ui.layout.VerticalLayout({
content: [
new sap.m.Label({
text: "{tableData>Status}"
}),
new sap.ui.core.Icon({
src: {
parts: ["tableData>Status"],
formatter: assets.util.mFormatter.formatStatusIcon
},
size: "1rem",
color: {
parts: ["tableData>Status"],
formatter: assets.util.mFormatter.formatStatusIconColor
}
})
]
})
colItems.addCell(txtNAME3);
oTable.bindAggregation("items", "tableData>/items", colItems);
oTable.setModel(oModel, "tableData");
Formatter.js
jQuery.sap.declare("assets.util.mFormatter");
assets.util.mFormatter = {
formatStatusIcon: function(Status) {
return (Status === "2" ? "ICONPath1" : "ICONPath2");
},
formatStatusIconColor: function(Status) {
return (Status === "2" ? "Color1" : "Color2");
},
};
Output
Your syntax is wrong I think. Remove that parts stuff.
Try this:
src="{path: 'invoice>Status',
formatter: '.Formatter.statusText'}
Try this syntax below :
new sap.ui.layout.VerticalLayout({
content: [
new sap.m.Label({text:"{Items>Status}"}),
new sap.ui.core.Icon({
src: {
parts: [
{path: 'Items>Status'}
],
formatter: '.Formatter.formatStatusIcon'
},
size: "1rem",
color: {
parts: [
"Items>Status"
],
formatter: Formatter.formatStatusIconColor
}
})
]
})

Overlapping of two buttons in SAPUI5

I want to create a content table using SAPUI5 but when I am trying to add more than one button they are getting overlapped.
Code:
var page2 = new sap.m.Page("page2",{
title : "Contents",
showNavButton : true,
navButtonPress : function() {
app.back();//go back to previous page
},
content : new sap.m.Button({
text : "Introduction",
press : function() {
app.to("page3");//navigate to Home
},
//enabled : false
type : sap.m.ButtonType.Transparent
}),
content : new sap.m.Button({
text : "Iview",
press : function() {
app.to("page3");//navigate to Home
},
//enabled : false
type : sap.m.ButtonType.Transparent
})
});
var Button1 = new sap.m.Button({
text : "Introduction",
press : function() {
//navigate to Home
app.to("page3");
},
//enabled : false
type : sap.m.ButtonType.Transparent
});
var Button2 = new sap.m.Button({
text : "Iview",
press : function() {
//navigate to Home
app.to("page3");
},
//enabled : false
type : sap.m.ButtonType.Transparent
})
var page2 = new sap.m.Page("page2",{
title : "Contents",
showNavButton : true,
navButtonPress : function() {
//go back to previous page
app.back();
},
content : [Button1, Button2]
});
page2.placeAt("body");

List selection issue while using CustomListItem and StandardListItem inside the List with includeItemInSelection

I have the following view, which has List and I have set includeItemInSelection property to true. And there I have attached to selectionChange event also.
<mvc:View
controllerName="com.naveen.test.list.controller.List"
xmlns="sap.m"
xmlns:mvc="sap.ui.core.mvc"
height="100%">
<List
selectionChange="onSelectionChange"
includeItemInSelection = "true"
mode = "MultiSelect"
items="{
path: '/data',
factory: '.listItemFactory'
}">
</List>
</mvc:View>
Mainly the list items are going to be instantiated via factory method listItemFactory as follows in the controller.
listItemFactory : function(sId, oContext) {
var each = oContext.getObject();
var listItem = null;
if( each.type === 'Group' ) {
var childList = new List({
includeItemInSelection : true,
selectionChange : jQuery.proxy(this.onSelectionChange,this),
mode : "MultiSelect"
});
childList.bindItems({
path : 'childData',
factory : jQuery.proxy(this._childListFactory, this)
});
listItem = new CustomListItem({
selected : '{selected}',
content : [childList]
});
} else {
listItem = this._childListFactory(sId, oContext);
}
return listItem;
},
_childListFactory : function(sId, oContext){
return new StandardListItem({
title : '{name}',
selected : '{selected}'
});
},
onSelectionChange : function(oEvent) {
console.log(oEvent);
}
And the json data for this as follows.
{
"data":[
{
"id" : "1",
"name" : "Name1",
"selected" : true,
"type" : "Normal",
"childData" : []
},
{
"id" : "2",
"name" : "Name2",
"selected" : false,
"type" : "Normal",
"childData" : []
},
{
"id":"LAYER15",
"name":"Name3",
"selected":true,
"type":"Group",
"childData" : [
{
"id":"3-1",
"name":"Name3-1",
"selected":true
},
{
"id":"3-2",
"name":"Name3-2",
"selected": false
},
{
"id":"3-3",
"name":"Name3-3",
"selected":true
}
]
}
]
}
But When we click on the child list item it will fire the event for that child list item also and for the Parent list item also. How to stop the parent event for that one item.
FYI, Click on the item which has the title Name3-2.
See the console there will be two logs.
try using preventDefault() function of jQuery.
https://developer.mozilla.org/en/docs/Web/API/Event/preventDefault

Custom control Openui5

sap.ui.core.Element.extend("custom.barNlineChartControl", { metadata : {
properties : {
"Job" : {type : "string", group : "Misc", defaultValue : null},
"Threshold" : {type : "int", group : "Misc", defaultValue : null},
}
}});
sap.ui.core.Control.extend("control.barNlinechart", {
/* the control API */
metadata : {
aggregations : {
"items" : { type: "custom.barNlineChartControl", multiple : true, singularName : "item"}
},
events: {
"select" : {},
"selectEnd": {}
}
},
//D3 Code below:
onAfterRendering: function() {
var that = this;
/* get the Items aggregation of the control and put the data into an array */
var aItems = this.getItems();
var data = [];
for (var i=0;i<aItems.length;i++){
var oEntry = {};
for (var j in aItems[i].mProperties) {
oEntry[j]=aItems[i].mProperties[j];
}
data.push(oEntry);
}
alert(JSON.stringify(data));
Code of view & control
multiBarLineGraph = new control.barNlinechart({
layoutData: new sap.ui.layout.GridData({span: "L12 M12 S12"}),
items: {
path : "/genericData",
template : new custom.barNlineChartControl({Job:"{Job}",Threshold:"{Threshold}"}),
}
}),
var multiBarData = {
"genericData":[
{
"Job": "Doctor",
"Threshold": 45,
"Hospital1": 30,
"Hospital2": 100,
"Hospital3": 90,
},
{
"Job": "Teacher",
"Threshold": 65,
"School1": 60,
"School2": 75,
},
]};
When the alert in d3 code executes I get Job & Threshold but other data from JSON array are missing which is obvious as the properties set here only accept job and threshold. As the JSON is dynamic how to write custom control so that I can pass the complete data to control everytime no matter how dynamic the data be.
You could use type: "any" for your items and dont use the element custom.barNlineChartControl at all:
Edit: as an aggregation controls the lifetime of the aggregated objects you have to use a property in this case.
sap.ui.core.Control.extend("control.barNlinechart", {
/* the control API */
metadata : {
properties : {
"items" : { type: "any" }
},
events: {
"select" : {},
"selectEnd": {}
}
},
and then in your view:
multiBarLineGraph = new control.barNlinechart({
layoutData: new sap.ui.layout.GridData({span: "L12 M12 S12"}),
items: { path : "/genericData" }
}),
this.getItems() would return an array of whatever has been been set / bound.

How to get content of a row in sap.m.table

So basically My problem is I have a page:
var page1 = new sap.m.Page({
title: "Something",
enableScrolling : true,
content : [
oTable = new sap.m.Table("items", {
columns : [
new sap.m.Column({
styleClass : "name",
hAlign : "Left",
header : new sap.m.Label({
text : "firstColumn"
})
})
]
})]
});
var template = new sap.m.ColumnListItem({
type : "Navigation",
cells : [
new sap.m.Label({
text : "{name}"
})
]
});
template.attachPress(function(oEvent){
var selectedRowContext = oEvent.getParameter("item");
alert(selectedRowContext);
});
Here I want to get the selectedRowContext and I don't know how?
Thank you
If you are binding data try
this.getBindingContext(/*modelName?*/)
or
oEvent.getSource().getBindingContext(/*modelName?*/)
//oControlEvent is the argument from the attachpress event
var selectedData = oControlEvent.getParameters().rowBindingContext.getModel().getData();
var selectedPath = oControlEvent.getParameters().rowBindingContext.getPath();
var selectedIndex = selectedPath.split("/")[selectedPath.split("/").length - 1];
selectedData = selectedData[OBJECTNAME][selectedIndex];