on 2012 May 22 5:28 PM
Hi,
As part of my blog on sapui5 vs phonegap, I wanted to do data binding between phonegap exposed api and a sapui5 table view.
I looked at the contacts api, for which Phonegap returns the data in JSON format in a similar structure as the test case below.
var contacts = {
modelData:
[
{
displayName:"Dagfinn Parnas",
nickname:"Dagi",
phoneNumbers: [
{type:"mobile", number:"9364xxxx"},
{type:"home", number:"5165xxxx"},
],
},
{
displayName:"John Doe",
nickname:"Doh",
phoneNumbers: [
{type:"mobile", number:"952xxxxx"},
{type:"other", number:"5165xxxx"},
],
},
{
displayName:"Jane Doe",
nickname:"Doh",
phoneNumbers: [
{type:"mobile", number:"12hxxxxx"},
],
},
]
};
As you can see, each contact has an array of phone numbers with varying type.
What I wanted to do is to bind the phoneNumbers which has type "mobile" to one sap.ui.table.Column, and those with type "home" to another one.
Unfortunately, I was not able to do this.
Is it possible to achieve it with sapui5 beta?
The closest I came is this test case.
It bind the first number to the first column and the second number to the second column.
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>sapui5 databinding</title>
<script src="/sapui5/resources/sap-ui-core.js"
type="text/javascript"
id="sap-ui-bootstrap"
data-sap-ui-libs="sap.ui.commons,sap.ui.table"
data-sap-ui-theme="sap_goldreflection">
</script>
<script>
jQuery.sap.log.setLevel(jQuery.sap.log.LogLevel['DEBUG']);
var contacts = {
modelData:
[
{
displayName:"Dagfinn Parnas",
nickname:"Dagi",
phoneNumbers: [
{type:"mobile", number:"9364xxxx"},
{type:"home", number:"5165xxxx"},
],
},
{
displayName:"John Doe",
nickname:"Doh",
phoneNumbers: [
{type:"mobile", number:"952xxxxx"},
{type:"other", number:"5165xxxx"},
],
},
{
displayName:"Jane Doe",
nickname:"Doh",
phoneNumbers: [
{type:"mobile", number:"12hxxxxx"},
],
},
]
};
var oTable = new sap.ui.table.DataTable();
//two columns with simple binding
oTable.addColumn(new sap.ui.table.Column({
label: new sap.ui.commons.Label({text: "Name1"}),
template: new sap.ui.commons.TextView().bindProperty("text", "displayName"),
sortProperty: "displayName"
}));
oTable.addColumn(new sap.ui.table.Column({
label: new sap.ui.commons.Label({text: "Name2"}),
template: new sap.ui.commons.TextView().bindProperty("text", "nickname"),
sortProperty: "nickname",
}));
var oTVNumber1 = new sap.ui.commons.TextView();
oTVNumber1.bindProperty("text","phoneNumbers/0/number");
oTable.addColumn(new sap.ui.table.Column({
label: new sap.ui.commons.Label({text: "Number1"}),
template:oTVNumber1,
sortProperty: "id",
}));
var oTVNumber2 = new sap.ui.commons.TextView();
oTVNumber2.bindProperty("text","phoneNumbers/1/number");
oTable.addColumn(new sap.ui.table.Column({
label: new sap.ui.commons.Label({text: "Number2"}),
template:oTVNumber2,
sortProperty: "id",
}));
var oItemTemplate2 = new sap.ui.core.ListItem();
oItemTemplate2.bindProperty("text", "type").bindProperty("additionalText", "number");
var oListTemplate = new sap.ui.commons.ListBox("myLb3", {displaySecondaryValues:true, height:"200px"});
oListTemplate.bindAggregation("items", "phoneNumbers", oItemTemplate2);
oTable.addColumn(new sap.ui.table.Column({
label: new sap.ui.commons.Label({text: "Phone"}),
//template: new sap.ui.commons.ComboBox().bindItems("phoneNumbers", oListItemTemplate),
template:oListTemplate,
sortProperty: "id",
}));
//create model
var oModel = new sap.ui.model.json.JSONModel();
//set model with a new root element
oModel.setData(contacts);
//bind model to table
oTable.setModel(oModel);
//bind table to the root element in the model
oTable.bindRows("modelData");
oTable.placeAt("dataTable");
//list test 1
var oLB = new sap.ui.commons.ListBox("myLb", {displaySecondaryValues:true, height:"200px"});
oLB.setModel(oModel);
oLB.bindContext("/modelData/1");
var oItemTemplate = new sap.ui.core.ListItem();
oItemTemplate.bindProperty("text", "type").bindProperty("additionalText", "number");
oLB.bindAggregation("items", "phoneNumbers", oItemTemplate);
oLB.placeAt("list1");
//TextView test
</script>
</head>
<body class="sapUiBody">
<h1>sapui5 databinding</h1>
<div id="dataTable"></div>
<div id="singleproperty"></div>
<div id="list1"></div>
<div id="list2"></div>
</body>
</html>
Request clarification before answering.
Hi Dagfinn,
I don't think binding directly to the table is possible, but this seams to be more a Javascript problem.
You may try to extend the model data on the fly, something like this (haven't tested yet, but you see, what I mean):
for data in modelData {
for phoneNumber in phoneNumbers{
data[phoneNumber["type"]] = phoneNumber["number"];
};
};
And then you should be able to bind the new fields modelData.mobile, modelData.home and mobileData.others to the columns. This is more a workaround than a solution, I know.
Best regards
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Thanks Uwe,
Yes, flattening the json or java object would be the workaround in this case.
And your method is quite elegant I must say.
However, the json structure returned by phonegap is often used in services and it should not be necessary to flatten it. Flattening it will also make it very hard to have a two-way binding with the model.
My suggestion would be to introduce the possibility of a computed property that is bindable.
Knockoutjs framework has a computed observable that serves this purpose
"That’s where computed observables come in - these are functions that are dependent on one or more other observables, and will automatically update whenever any of these dependencies change."
http://knockoutjs.com/documentation/computedObservables.html
Here is an example
//this is a standard property
this.lastName = ko.observable("Bertington");
//this is a computed once
this.mobile = ko.computed(function(){
for phoneNumber in this.phoneNumbers{
if(phoneNumber.type=='mobile'){
return phoneNumber.number;
}
return null;
}
I would love to sapui5 also get this feature and hope someone from the sapui5 team can comment on that.
Regards
Dagfinn
Hi Dagfinn,
did you notice the 3rd parameter of the bindProperty function? It allows you to e.g. pass a formatter function for the binding which can be used to intercept a value and afterwards adopt this value and return something computed as you called it.
Here is a sample for the property binding of the "home" phone number column:
var oTVNumber1 = new sap.ui.commons.TextView();
oTVNumber1.bindProperty("text", "phoneNumbers", function(aValue) {
var sNumber = "";
if (aValue) {
jQuery.each(aValue, function(iIndex, oValue) {
if (oValue.type === "home") {
sNumber = oValue.number;
return false; // break
}
});
}
return sNumber;
});
oTable.addColumn(new sap.ui.table.Column({
label: new sap.ui.commons.Label({text: "Home"}),
template:oTVNumber1
}));
As value of the formatter function you receive the object/array containing the phone numbers.
Is this what you was looking for?
Best regards,
Peter
Great discussion!
I took the liberty of cleaning up the sample code and adding the dynamic formatter function that Peter pointed out. I investigated making this sort of thing a little bit more generic, see what you think.
Gist here: https://gist.github.com/2788164
Cheers
dj
Hello,
I've tested you code, but the table is not getting filled like it should look at the screenshot below:
I'm running the code on my local test server for netweaver cloud.
Can you please help me?
Code I used:
Hi Vincent
Interesting find. I'm guessing you're using the latest SAPUI5 version (1.8.4) which was recently made available.
There's a subtle difference between the binding path between the table and the JSON model. What worked prior to 1.8.4 was a relative path at the root, i.e.
oTable.bindRows("modelData");
but in fact what is required now is an absolute path, i.e.
oTable.bindRows("/modelData");
You can see the difference if you run your code (http://pastie.org/5406392) in Chrome against a 1.8.4 release, and then in the developer tools JavaScript console re-bind by entering:
oTable.bindRows("/modelData");
and you should see the data appear in the table.
Note also that even though it still works, DataTable is now deprecated in 1.8.4.
cheers
dj
Actually also just found this comment on another post here which confirms this:
Hi DJ,
Great solutions! Thanks so much for posting it. Now I have a similar case where I need to create a select list with different values for each row. My data looks like this:
var questions = {"ques" : [
{
"Q" : Description ID1,
"Opt" : [{"Options":Option1},
{"Options":Option2},
{"Options":Option3},
{"Options":Option4}]
},
{
"Q" : Description ID2,
"Opt" : [{"Options":Option1},
{"Options":Option2},
{"Options":Option3},
{"Options":Option4}]
},
{
"Q" : Description ID3,
"Opt" : [{"Options":Option1},
{"Options":Option2},
{"Options":Option3},
{"Options":Option4}]
},
{
"Q" : Description ID4,
"Opt" : [{"Options":Option1},
{"Options":Option2},
{"Options":Option3},
{"Options":Option4}]
},
{
"Q" : Description ID5,
"Opt" : [{"Options":Option1},
{"Options":Option2},
{"Options":Option3},
{"Options":Option4}]
}
]
};
Thanks so much any tips!
Cheers,
Ron
Hi guys,
I want to pass a single value from Page1 to Page2 in a SAPUI5 Mobile APP. Then on page 2 I want to use this value for some logic implementation. Please guide me how can i pass a single value between 2 pages and then how to access/use this value on the second page.
Thanks and best regards.
Fahad
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
64 | |
8 | |
7 | |
7 | |
6 | |
5 | |
5 | |
4 | |
4 | |
4 |
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.