How to bind OData directly to XMLView - data-binding

I have an UI5 app in which I have a table defined in my XMLView. I'm making a call to the backend using OData to retrieve the data. I'm doing it the following way.
var oModel = new sap.ui.model.odata.ODataModel("url to data", true);
var inputModel = new JSONModel();
oModel.read("/Products",
null,
null,
false,
function _OnSuccess(oData, response) {
var data = oData.results;
inputModel.setData(data);
},
function _OnError(error) {
console.log(error);
});
//set model(s) to current xml view
this.getView().setModel(inputModel, "inputModel");
How can I do this without having to create the JSON model, I mean bind the oData directly to the XMLView.
I have seen it being done but only with JSView, e.g:
var oModel = new sap.ui.model.odata.v2.ODataModel("http://admin- think:88/sap/...",{useBatch : true});
sap.ui.getCore().setModel(oModel,"model1");
// Create instance of table
var oTable = new sap.ui.table.Table({
visibleRowCount : 6,
selectionMode: sap.ui.table.SelectionMode.Single,
navigationMode: sap.ui.table.NavigationMode.scrollbar,
selectionBehavior: sap.ui.table.SelectionBehavior.RowOnly
});
// First column "Application"
oTable.addColumn(new sap.ui.table.Column({
label : new sap.ui.commons.Label({
text : "APPLICATION",
textAlign : "Center",
}),
template : new sap.ui.commons.TextView({
textAlign:"Center"}).bindProperty("text","model1>Applno"),
}));
// Bind model to table control
oTable.bindRows("model1>/");
This way it seems like a lot of work. How can I do something like this but using an XML view?

XML Code :
<mvc:View
controllerName="sap.m.sample.Table.Table"
xmlns:l="sap.ui.layout"
xmlns:mvc="sap.ui.core.mvc"
xmlns="sap.m">
<Table id="idProductsTable"
inset="false"
items="{Data>/Table}">
<columns>
<Column>
<Text text="Name" />
</Column>
<Column>
<Text text="id" />
</Column>
</columns>
<items>
<ColumnListItem>
<cells>
<Text
text="{Data>name}" />
<Text
text="{Data>id}" />
</cells>
</ColumnListItem>
</items>
</Table>
</mvc:View>
JS Code :
onAfterRendering : function(){
var oView = this.getView();
var oTableJSON = new sap.ui.model.json.JSONModel();
var fnSuccess = function(oEvent,oResponse){
var Data = {
Table : oData.results,
};
oTableJSON.setData(Data);
oView.byId("idProductsTable").setModel(oTableJSON,"Data");
};
oModel("/ProductionSet",null,null,true,fnSuccess,fnFail);
}

Related

SAPUI5 How to display only the first value of an entitySet

I'm currently working on an app for displaying some data, which I get from an EntitySet.
The mockup for my application looks like this:
On the top, I have an input Field with a button to apply the filter with the value of the input.
After that, there are 5 ObjectListItems at the moment. I don't know if its the right thing to use.
Under these boxes, there is a table to display further information about the chosen entry. The table works as intended and looks good.
My Problem now lies within these 5 Boxes.
{Binding1} to {Binding5} contains always the same Value for one giving "Input Value". Which means, {Binding1} for example would be 7 times Value1 and {Binding2} 7 times Value2. Now i want these to be shown only one time in there own Box.
Values, which are differ per row, are shown in the table below.
I don't know how I could make this work...
View:
<l:VerticalLayout width="100%">
<l:BlockLayout background="Dashboard">
<l:BlockLayoutRow>
<l:BlockLayoutCell width="100%">
<Title text="Test {Binding1} - {Binding2}"/>
</l:BlockLayoutCell>
</l:BlockLayoutRow>
<l:BlockLayoutRow>
<l:BlockLayoutCell width="50%">
<ObjectListItem
intro="Site"
icon="sap-icon://building"
title="{Binding3}"
/>
</l:BlockLayoutCell>
<l:BlockLayoutCell width="50%">
<ObjectListItem
intro="Adress"
icon="sap-icon://addresses"
title="{Binding4}"
/>
</l:BlockLayoutCell>
</l:BlockLayoutRow>
<l:BlockLayoutRow>
<l:BlockLayoutCell width="50%">
<ObjectListItem
intro="Supplier"
icon="sap-icon://supplier"
title="{Binding5}"
/>
</l:BlockLayoutCell>
<l:BlockLayoutCell width="50%">
<ObjectListItem
intro="Currency"
icon="sap-icon://lead"
title="{Binding6}"
/>
</l:BlockLayoutCell>
</l:BlockLayoutRow>
</l:BlockLayout>
</l:VerticalLayout>
<Table
id="table1"
items="{path: '/EntitySet'}">
<columns>
<Column>
<Text text="Category"/>
</Column>
...
</columns>
<items>
<ColumnListItem>
<cells>
<Text text="{Category}"/>
...
</cells>
</ColumnListItem>
</items>
</Table>
Controller:
return Controller.extend("com.zf.cmi.zz1ui5_ivdp.controller.View", {
onInit: function() {
},
onPress: function() {
var oTable = this.getView().byId("table1");
var oTableBinding = oTable.getBinding("items");
var filter = new sap.ui.model.Filter("InvoiceNo", sap.ui.model.FilterOperator.EQ, this.byId("search").getValue());
oTableBinding.filter(filter);
}
});
Is there a way to show the value of {Binding1} - {Binding5} only one time at their given Box?
*edit
As an addition, the result of my XML model would look like this:
Entry1: Entry2: Entry3:
Binding1 = a Binding1 = a Binding1 = a
Binding2 = b Binding2 = b Binding2 = b
Binding3 = ... Binding3 = ... Binding3 = ...
Binding10 = 1 (Table) Binding10 = 2 Binding10 = 3
If It's a JSON Model you can use binding path like this {/Binding1/0}.
If It's a XML Model you need to know the KEY to set the binding path like this {/Binding1('Key')}. If you don't know the key, you have to use JS in controller to get it or change/create your service to return the data in an away better to you UI5 show it.
Using JS Controller
onInit: function () {
this.getView().bindElement({
path: "/BINDING_PATH",
events: {
dataReceived: function (oEvent) {
var data = oEvent.getParameter('data');
var array_paths = oEvent.getSource().getModel();
}.bind(this),
}
});
}
Now on data you have all data returned by service, and on array_path you have an array with path and data, you can get the array KEY (that's the service path) to binding to your controls.
<ObjectListItem
intro="Site"
icon="sap-icon://building"
title="{/EntrySet('1')/Binding3}" />
is the same as
<ObjectListItem
binding="{/EntrySet('1')}"
intro="Site"
icon="sap-icon://building"
title="{Binding3}" />
is the same as
<ObjectListItem
id="Item3"
intro="Site"
icon="sap-icon://building"
title="{Binding3}" />
const iID = 1;
const sKey = "/EntrySet('" + iID + "')";
this.byId("Item3").bindElement(sKey);
You can then replace iID with something meaningful depending on the input.

variable in iframe with zk

i have a for each in my zk page, and in the each i am creating a column, and in my column i need add a iframe, and to each frame i need pass as variable the label of the column.
I have something like:
<zk>
<window title="Dynamic Columns" border="normal" width="1824px" apply="org.zkoss.bind.BindComposer" viewModel="#id('vm') #init('pkg$.DynamicColumnModel')">
<grid >
<columns>
<column forEach="${vm.columnList}" label="${each}">
<iframe
src="test.zul" />
</column>
</columns>
</grid>
</window>
</zk>
But i have an error when i include the page, and my first problem is that i do not know how can i pass a variable to each iframe.
And my java is something like:
public class DynamicColumnModel {
private List<String> columnList = new ArrayList<String>();
private String texto="123";
#Init
public void init(){
columnList.add("Dynamic Col A");
columnList.add("Dynamic Col B");
columnList.add("Dynamic Col C");
columnList.add("Dynamic Col D");
}
public List<String> getColumnList() {
return columnList;
}
public void setColumnList(List<String> columnList) {
this.columnList = columnList;
}
public String getTexto() {
return texto;
}
public void setTexto(String texto) {
this.texto = texto;
}
#Command
public void mensaje(){
}
}
Thanks
If your each is a String, which it appears to be as you set it as the column label, just go ahead and pass it as a URL parameter to the iframe.
<window apply="org.zkoss.bind.BindComposer"
viewModel="#id('vm') #init('pkg$.DynamicColumnModel')">
<grid >
<columns>
<column forEach="${vm.columnList}" label="${each}">
<iframe src="test.zul?myValue=${each}" />
</column>
</columns>
</grid>
</window>
Note that when you are using an iframe component, you are stepping outside ZK. True, the iframe itself points to a ZK page, but it's a not within the same ZK environment. The iframe could just as easily include www.google.com and so there is no specific ZK support for passing values to ZK pages included in this manner.
If you're only including ZK pages and want to pass information to these pages more fluidly, you'll want to use ZK's include tag. Have a look at the documentation on how to pass values to included ZK pages.
Edit
If going the iframe route, you can access URL parameter values from test.zul using ZK's Execution class:
Execution execution = Executions.getCurrent();
execution.getParameter("myValue");

Fill dropdown list from xml with linq

i have the following xml doc:
<?xml version="1.0" encoding="utf-8" ?>
<dropdowns>
<dropdown name="DropDownLoc">
<menu text="Select" value="-1" />
<menu text="North" value="1200" />
<menu text="South" value="1400" />
</dropdown>
<dropdown nome="DropDownEsp">
<menu text="Select" value="-1" />
<menu text="Est" value="7" />
<menu text="Ovest" value="9" />
</dropdown>
</dropdowns>
I want to read this xml and fill two dropdowns with a method given the dropdownlist name (like "DropDownEsp")
I want to accomplish this with linq, who can help me please ?
Below is code which would help you read XML and create a list of items (ListItem):
// or use XDocument.Parse("xml string") to parse string
XDocument xdoc = XDocument.Load(#"c:\testxml.xml");
var dropLists = xdoc.Descendants("dropdown")
.Select(d => d.Descendants("menu").Select(m =>
new /* new ListItem(text, value) */
{
Text = m.Attribute("text"),
Value = m.Attribute("value")
}))
.ToList();
Try adding items into controls yourself.
If you have an empty <asp:DropDownList ID="DynamicDropDown" runat="server" /> control on your .aspx page, you can data bind it a the results of a LINQ query like this:
protected void Page_Load(object sender, EventArgs e)
{
if(!Page.IsPostBack)
{
// Assuming your XML file is in the App_Data folder in the root of your website
string path = Server.MapPath("~/App_Data/DropDowns.xml");
// Let's say we want to use the options from the second <dropdown>-tag in your XML
string whichDropDown = "DropDownEsp";
// This is the LINQ query to find those options from the XML
// and turn them into ListItem objects
var query =
from dropDown in XDocument.Load(path).Descendants("dropdown")
where dropDown.Attribute("name").Value == whichDropDown
from name in dropDown.Descendants("name")
let text = name.Attribute("text").value
let value = name.Attribute("value").value
select new ListItem(text, value);
// Now we data bind the query result to the control
DynamicDropDown.DataSource = query;
DynamicDropDown.DataBind();
}
}
In the LINQ query we first select only the <dropdown> element with the right name (based on the whichDropDown variable). Then we select all the <name> elements, and from each one we put the attributes in the text and value values. Then we use these values to create a new ListItem (one is created for each <name> element).
This result can then be used to data bind the <asp:DropDownList> control.

How to display images from sqlite into a flex datagrid

I have a number of thumbnail images (8K ish in length), stored in a sqlite database, encoded as base64 strings.
I would like to retrieve these images and present them into a datagrid (along with some other information from the DB)
The retrieval of information from the database works, but I cannot quite "see" how to connect the decoded result from the database to the datagrid, to display the images.
Below is some code, where I show (to simplify things) a simply DGrid and want to use the dataprovider to point to the select from the DB
Any details to show how I need to change this code would be greatly appreciated:-)
<mx:DataGrid id="dg2" dataProvider="{dp2}">
<mx:columns>
<mx:DataGridColumn headerText="Image" dataField="image" width="150"/>
</mx:columns>
</mx:DataGrid>
The code to generate the dp2 information is as follows.
The result2 array is populated as expected and ldr appears to be populated, but imageBMap and (therefore) dp2 are null.
sql2.text = "SELECT image FROM bookMarks;";
sql2.execute();
var result2:SQLResult = sql2.getResult();
var data2:Array = result2.data;
var base64Dec:Base64Decoder;
var byteArr:ByteArray;
var bmap:Bitmap;
var ldr:Loader = new Loader();
base64Dec = new Base64Decoder();
if(result2.data != null)
{
var numRows:int = result2.data.length;
for(var i:int = 0; i < numRows; i++)
{
for(var columnName:String in result2.data[i])
{
if(columnName == "image") // Normally there will be more than 1 column in the select, hence this check
{
base64Dec.decode(result2.data[i][columnName]);
byteArr = base64Dec.toByteArray();
ldr.contentLoaderInfo.addEventListener(Event.COMPLETE, loaderComplete);
ldr.loadBytes(byteArr);
}
}
}
}
var imageBMap:Bitmap = Bitmap(ldr.content);
dp2 = ArrayCollection(imageBMap);
}
private function loaderComplete(event:Event):void
{
var loaderInfo:LoaderInfo = LoaderInfo(event.target);
var bitmapData:BitmapData = new BitmapData(loaderInfo.width, loaderInfo.height, false, 0xFFFFFF);
bitmapData.draw(loaderInfo.loader);
}
You need to use in itemRenderer to display the image:
<mx:DataGridColumn headerText="Image" width="150">
<mx:itemRenderer>
<fx:Component>
<s:Image source="{here you put the dataProvider}">
</fx:Component>
</mx:itemRenderer>
</mx:DataGridColumn>

Flex 3 StringValidator Highlight Field

I want to perform simple validation against multiple fields. Please note these fields are not within a mx:Form since the way they are displayed isn't the norm. The validation works properly, however, it does not highlight the textInput with the error message.
myValidator.source = empName1;
myValidator.property = "text";
if(myValidator.validate().type == ValidationResultEvent.VALID)
{
Alert.show("good");
}
...
<mx:StringValidator id="myValidator" required="true" minLength="1" requiredFieldError="This field is required" />
<mx:TextInput x="152" y="32" width="207" id="empName1"/>
Please note I want to use the same validator "myValidator" against multiple fields which is why the source and property are set in the actionscript 3 code.
Thanks
Update:
heres a similar function I created that works:
private function validateField(fields:Array):Boolean
{
var rtnResult:Boolean = true;
for each(var i:Object in fields)
{
myValidator.source = i;
myValidator.property = "text";
i.validateNow();
if(myValidator.validate().type == ValidationResultEvent.INVALID)
rtnResult = false;
}
return rtnResult;
}
which is called like so:
if(!validateField([TicketTitle,TicketDesc]))
{
Alert.show("Required fields were left blank!", "Warning");
return;
}
and the mxml validator
<mx:StringValidator id="myValidator" required="true" minLength="1" requiredFieldError="This field is required" />
Solved it... I needed this:
empName1.validateNow();

Resources