How to bind dynamic data to a table in sapui5? - sapui5

I am trying to bind dynamic data to a table created in xml. But I couldn't make it. I am not getting any errors but it always shows "No Data Available". Here is what I have tried.
App.view.xml :-
<sap.ui.layout:HorizontalLayout xmlns:sap.ui.layout="sap.ui.layout" id="table_layt">
<sap.ui.layout:content>
<Table noDataText="No Data Available" id="bud_table" class="table_layt">
<items></items>
<columns>
<Column id="c1">
<header><Label text="Account Description" id="aclab"/></header>
</Column>
<Column id="c2">
<header><Label text="Actual" id="actlab"/></header>
</Column>
<Column id="c3">
<header><Label text="Budget" id="budglab"/></header>
</Column>
<Column id="c4">
<header>
<Label text="Variance" id="valab"/></header>
</Column>
</columns>
</Table>
</sap.ui.layout:content>
App.controller.js :-
var oTable = this.getView().byId("bud_table");
var oTemplate = new sap.m.ColumnListItem({
cells:[
new sap.m.Label({
text:"{AccountDesc}"
}),
new sap.m.Text({
text:"{AmtActFore}"
}),
new sap.m.Text({
text:"{AmtBudget}"
}),
new sap.m.Text({
text:"{AmtVariance}"
})
]
});
oTable.bindItems("/root", oTemplate);
And my data looks like this :-
data
Object {root: Array[64]}
root: Array[64]
0: Object
AccountDesc: "blah"
AccountNo: "blah"
AmtActFore: "blah"
AmtBudget: "blah"
AmtVariance: "blah"

I think you're missing the part where you're pushing the data into a model:
this.getView().setModel(
new sap.ui.model.json.JSONModel({
root: [{
AccountDesc: "blah",
AccountNo: "blah",
AmtActFore: "blah",
AmtBudget: "blah",
AmtVariance: "blah"
}]
}));
Please refer to this JSBin for a working example of your code, including the model initialisation part.

Related

Table with Context Binding

I am an intern at SAP, and I am having some problem with Context binding in SAPUI5 for a table in an XML view.
So I am trying to create a dialog panel in SAPUI5 in an XML view so that if I click on a row in a table, then a separate popup/panel should come up above it and display more information about the product I clicked on
I have it working with javascript with:
var details = new sap.m.Panel("details",{
headerText: "This is the {name}",
visible: false,
content: [
new sap.m.Table({
alternateRowColors: true,
fixedLayout: false,
sticky: sap.m.Sticky.ColumnHeaders,
columns:[
new sap.m.Column({
header : new sap.m.Label({
text : "This is the Number of failed Tests: {coverage}"
})
}),
new sap.m.Column({
header : new sap.m.Label({
text : "This is the Number of Bugs: {unitTestCoverage}"
})
}),
new sap.m.Column({
header : new sap.m.Label({
text : "This is the P/F ratio: {unitFirstCoverage}"
})
})
]})
// dataTable
]
});
with in XML I have my details panel as:
<!--Details Panel!-->
<Panel id= "details"
headerText= "This is the {data>name}"
visible= "false">
<content>
<Table>
<columns>
<Column>
<header>
<Label text="This is the Number of failed Tests: {data>coverage}" />
</header>
</Column>
<Column>
<Label text="This is the Number of Bugs: {data>unitTestCoverage}" />
</Column>
<Column>
<Label text="This is the P/F ratio: {data>unitFirstCoverage}" />
</Column>
</columns>
<items>
</items>
</Table>
</content>
</Panel>
I am calling the row within the XML with this snippet:
............
<items>
<ColumnListItem
press= "onItemSelected"
type= "Active">
<cells>
.........
With the controller context binding it with:
onItemSelected: function(oEvent) {
var oSelectedItem = oEvent.getSource();
var sPath = oSelectedItem.getBindingContextPath();
var oProductDetailPanel = this.byId("details");
oProductDetailPanel.bindElement({ path: sPath });
this.byId("details").setVisible(true);
},
I suspect that i am going wrong with how I am trying to call the data in my details panel in XML, and how the data gets binded at the end
try this.
var sPath = oSelectedItem.getBindingContextPath()
with
var sPath = oSelectedItem.getBindingContext('data').getPath()
Alongside:
oProductDetailPanel.bindElement({ path: 'data>' + sPath });

How to Remove Row from Table

This question is a follow up to this: Button to add new row in SAPUI5 table
In my new scenario, I have added a "remove" button in the first column of the table. Again, the JSON file looks like this:
{
"Invoices": [
{
"ProductName": "Pineapple",
"Quantity": 21,
"ExtendedPrice": 87.2000,
"ShipperName": "Fun Inc.",
"ShippedDate": "2015-04-01T00:00:00",
"Status": "A"
},
...
]
}
My view now looks like this:
<mvc:View controllerName="stepbystep.demo.wt.controller.App" xmlns:mvc="sap.ui.core.mvc" xmlns="sap.m" xmlns:core="sap.ui.core"
xmlns:html="http://www.w3.org/1999/xhtml" displayBlock="true">
<Table id="ins" items="{ path : 'invoice>/Invoices', sorter : { path : 'ProductName' } }">
<headerToolbar>
<Toolbar>
<Button icon="sap-icon://add" text="Row" press="addRow"/>
<Button icon="sap-icon://display" text="Row" press="fetchRecords"/>
</Toolbar>
</headerToolbar>
<columns>
<Column width="50px"/>
<Column hAlign="Right" minScreenWidth="Small" demandPopin="true" width="4em">
<Text text="{i18n>columnQuantity}"/>
</Column>
<Column>
<Text text="{i18n>columnName}"/>
</Column>
<Column minScreenWidth="Small" demandPopin="true">
<Text text="{i18n>columnStatus}"/>
</Column>
<Column minScreenWidth="Tablet" demandPopin="false">
<Text text="{i18n>columnSupplier}"/>
</Column>
<Column hAlign="Right">
<Text text="{i18n>columnPrice}"/>
</Column>
</columns>
<items>
<ColumnListItem type="Navigation" press="onPress">
<cells>
<Button icon="sap-icon://delete" press="deleteRow" type="Reject"/>
<ObjectNumber number="{invoice>Quantity}" emphasized="false"/>
<ObjectIdentifier title="{invoice>ProductName}"/>
<Text text="{ path: 'invoice>Status', formatter: '.formatter.statusText' }"/>
<Text text="{invoice>ShipperName}"/>
<ObjectNumber
number="{ parts: [{path: 'invoice>ExtendedPrice'}, {path: 'view>/currency'}], type: 'sap.ui.model.type.Currency', formatOptions: { showMeasure: false } }"
unit="{view>/currency}" state="{= ${invoice>ExtendedPrice} > 50 ? 'Error' : 'Success' }"/>
</cells>
</ColumnListItem>
</items>
</Table>
And I have a function for adding a row (this one works fine):
addRow: function() {
this.getView().getModel("invoice").create("/Invoices", {
ProductName: "",
Quantity: "",
ShippedDate: "",
Status: ""
});
}
And I am trying to build one for deleting. This is what I have so far:
deleteRow: function(oArg) {
// var array = oArg.oSource.sId.split("-");
// var index = array[array.length - 1];
var path = oArg.oSource.oPropagatedProperties.oBindingContexts.invoice.sPath;
delete this.getView().getModel("invoice").oData[path.substr(1)];
this.getView().getModel("invoice").refresh(true);
}
But the row gets emptied and then returns again (like getting fetched from the mock server again). I am trying to completely remove the row (not just its contents), and the data to be removed.
I have seen plenty of examples online, but none cover my use case.
If you already use create for create new row then I think the best is to be consistent and use remove in order to remove it.
so in your case I think your code should look something like this:
this.getView().getModel("invoice").remove(path);
This line will do both:
Execute DELETE request to delete the object on the server (if you are using oDataModel)
Will delete the row from the table and refresh it because the table is bounded to this model
If you can please always use binding in your code. Using binding is much more efficient and easy to maintain because you don't need to deal with any DOM objects. The only thing that you need to do in code is creating/deleting/updating your model objects and UI5 runtime will do the rest for you.

SAPUI5: Refreshing table contents after oData.read

Im building an application with two textboxes, a button and a table. On pressing the button, an array of filters is composed from the contents of the textboxes and sent to my oData service in a read request. Right now, when one record is returned (as it shows in the console), the table will not be updated. What am I missing?
This is the table:
<Table id="PLTab" items="{/ORDSET}">
<headerToolbar>
<Toolbar>
<Title text="Planned Orders" level="H2" />
</Toolbar>
</headerToolbar>
<columns>
<Column>
<Text text="Product" />
</Column>
<Column>
<Text text="Planned Order" />
</Column>
<Column>
<Text text="Production Planner" />
</Column>
</columns>
<items>
<ColumnListItem>
<cells>
<ObjectIdentifier title="{Maktx}" text="{Matnr}" />
<Text text="{Ordno}" />
<Text text="{Name}" />
</cells>
</ColumnListItem>
</items>
</Table>
And this is the relevant part of the controller:
onInit: function() {
var oModel = this.getOwnerComponent().getModel("path");
oModel.refresh(true);
this.getView().setModel(oModel);
},
openOrders: function(oEvent) {
var PLFilters = [];
PLFilters.push(new sap.ui.model.Filter({
path: "Matnr",
operator: sap.ui.model.FilterOperator.EQ,
value1: this.getView().byId("Product").getValue()
}));
PLFilters.push(new sap.ui.model.Filter({
path: "Locno",
operator: sap.ui.model.FilterOperator.EQ,
value1: this.getView().byId("Location").getValue()
}));
var oModel = this.getOwnerComponent().getModel("path");
oModel.read("/ORDSET", {
filters: PLFilters,
success: function(oData, oResponse) {
console.log(oData);
}
});
}
Thanks & regards,
Max
var oModel = this.getOwnerComponent().getModel("path");
You use the model named "path" to read data, but in your XML View you use the default model (unnamed).
Try to change to
var oModel = this.getOwnerComponent().getModel();

Get selected item from sap.m.Select from a sapui5 table column

I am using sap.m.Table, where I have 3 columns, as sap.m.text, sap.m.setect and the last one is button.
My model code
var oModel = new sap.ui.model.odata.OData("url");
sap.ui.getCore().setModel(oModel ,"data");
Table view code(cells)
var oTemplate = new sap.m.ColumnListItem({
cells : [
new sap.m.Text({
text: "{data>Address}"
}),
new sap.m.Select({
id:"sel",
items: {
path: "data>/OPERATORS", // this is a diffent table
template: new sap.ui.core.Item({
text: "{data>firstName} {data>lastName}"
})
},
forceSelection: false
}),
new sap.m.Button({
text : "Start",
press : [oController.onPressStart, oController]
})
]
});
oTable.bindItems("data>/ORDR", oTemplate); //differnt table
Working fine, getting all required data on the specific table.(Notice first column is coming from ORDR table and second one is coming from OPERATORS table).
Now on button click I wanted the specific row data. My code as follows -
onPressStart : function(oEvent){
var obj = oEvent.getSource().getBindingContext("data").getObject();
},
"obj" gives me ORDR table row objects(where I pressed the button).
Now I also want the value I will select on the dropdown box. How to get it.
Please suggest, Thank you
JSbin Link - http://jsbin.com/quhomoloqo/edit?html,console,output
See this working example:
Please note how (for the sake of this question) created two models:
One named 'orig' which holds your original OPERATOR and ODRD data, and
one named 'data' which holds a copy of the OPERATOR data, with an added Address property.
See the view code on how the two models are used (the new one for the table, the old one for populating the dropdown)
sap.ui.controller("view1.initial", {
onInit : function(oEvent) {
},
onAfterRendering : function() {
// your original model
var oModel = new sap.ui.model.json.JSONModel();
var oData = {
"ODRD":[
{"Address":"UK"},
{"Address":"US"}
],
"OPERATORS":[
{"firstName":"a","lastName":"b"},
{"firstName":"c","lastName":"d"}
]
};
oModel.setData(oData);
this.getView().setModel(oModel, "orig");
// the model you actually need
var oNewModel = new sap.ui.model.json.JSONModel();
var oNewData = oData.OPERATORS.map(function(result) {
return {
firstName : result.firstName,
lastName : result.lastName,
keyToAddress : null
}
})
oNewModel.setData({
"OPERATORS" : oNewData
});
this.getView().setModel(oNewModel, "data");
},
showData : function(oEvent) {
alert(JSON.stringify(oEvent.getSource().getBindingContext("data").getObject()));
}
});
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-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" >
<Table id="tbl" items="{data>/OPERATORS}">
<columns>
<Column>
<Text text="First" />
</Column>
<Column>
<Text text="Last" />
</Column>
<Column>
<Text text="ODRD" />
</Column>
<Column>
<Text text="" />
</Column>
</columns>
<items>
<ColumnListItem>
<cells>
<Input value="{data>firstName}" />
<Input value="{data>lastName}" />
<Select items="{orig>/ODRD}" selectedKey="{data>keyToAddress}">
<items>
<core:ListItem key="{orig>Address}" text="{orig>Address}" />
</items>
</Select>
<Button text="Show data" press="showData" />
</cells>
</ColumnListItem>
</items>
</Table>
</mvc:View>
</script>

Dynamic content type of table cell

I get data from a database, make a model out of it and bind to a table.
I have a problem with one databse field that contains dataURL of the image or "Not Available" if no image is present.
The problem is that depending on the database field value, the cell of the table should be sap.m.Image or sap.m.Text.
And I can't get it to work.
Here is the relevant code part:
var signatureData = {};
signatureData.item = "Signature";
signatureData.value = data.signature;
var oModelSignature = new sap.ui.model.json.JSONModel();
oModelSignature.setData(signatureData);
var oSignatureTable = sap.ui.getCore().byId("reportDetailsSignature");
oSignatureTable.setModel(oModelSignature);
var oSignature;
if(data.signature == "Not Available"){
oSignature = new sap.m.Text({text: "{value}"});
}else{
oSignature = new sap.m.Image({src: "{value}", width: "7%", height: "7%"});
}
oSignatureTable.bindItems("/", new sap.m.ColumnListItem({
cells : [ new sap.m.Text({text: "{item}"}),
oSignature,]
}));
I have my table empty with "No data".
Since you're getting the value from data.signature only once, that will be the value your template will work with, regardless of whatever values it may have further in your model
A better approach will be to use a HBox as a template, with both an Image and a Text control, and using a formatter (see https://sapui5.hana.ondemand.com/sdk/#docs/guide/a2fe8e763014477e87990ff50657a0d0.html) you toggle the visibility for either of them.
(Forgive me for using XML syntax for the view, as that's my preferred style. But you can adapt to JS View easily):
EDIT: As an exercise for myself, I have created a running Code Snippet below.
// The UI5 controller
sap.ui.controller("view1.initial", {
onInit : function(oEvent) {
// a model with dummy data. Values are either empty or contain a URL
var oModel = new sap.ui.model.json.JSONModel();
oModel.setData({
rows : [
{ value : "sap-icon://syringe", col2 : "Value 2", col3 : "Value 3", ol4 : "Value 4" },
{ value : "", col2 : "Value 6", col3 : "Value 7", col4 : "Value 8" },
{ value : "sap-icon://account", col2 : "Value 10", col3 : "Value 11", col4 : "Value 12" },
{ value : "sap-icon://chalkboard", col2 : "Value 14", col3 : "Value 15", col4 : "Value 16" },
{ value : "sap-icon://e-care", col2 : "Value 18", col3 : "Value 19", col4 : "Value 20" },
{ value : "", col2 : "Value 22", col3 : "Value 23", col4 : "Value 24" }
]
});
this.getView().setModel(oModel);
},
// Formatter for icon visibility
setIconVisible : function (sValue) {
return !!sValue;
},
// Formatter for text visibility
setTextVisible : function (sValue) {
return !sValue;
}
});
// Code needed to place XML view into 'uiArea' DIV element
sap.ui.xmlview("main", {
viewContent: jQuery("#view1").html()
})
.placeAt("uiArea");
<!-- bootstrapper -->
<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-libs="sap.m"></script>
<!-- here the magic will be shown -->
<div id="uiArea"></div>
<!-- The XMLView definition -->
<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" >
<Table id="tbl" inset="true" multiSelect="true" selectionMode="MultiToggle" mode="MultiSelect"
items="{/rows}">
<columns>
<Column>
<Text text="Col1" />
</Column>
<Column>
<Text text="Col2" />
</Column>
<Column>
<Text text="Col3" />
</Column>
</columns>
<items>
<ColumnListItem>
<cells>
<!-- Notice how the cell contains a HBox with an Icon and Text control -->
<!-- Visibility will be toggled using the formatter function for both -->
<HBox>
<core:Icon src="{value}" visible="{path:'value', formatter:'.setIconVisible'}" />
<Text text="No data" visible="{path:'value', formatter:'.setTextVisible'}" />
</HBox>
<Text text="{col2}" />
<Text text="{col3}" />
</cells>
</ColumnListItem>
</items>
</Table>
</mvc:View>
</script>
The problem in my code was the absence of an array in my signatureData object.
After I added the above object into an array which is included in another object, the data appeared in the table.
Here is a working example.
If the value of signature key is a data URL of the image (or a link to it), the image is shown.