Combobox in sap.ui.table.Table - sapui5

I want to set values in a Combobox in the table: It does not show me the values ? Here is the code:
View:
<Column width="10rem">
<m:Label text="{i18n>Status}" />
<template>
<m:ComboBox items="{items>/Status}"
templateShareable="true">
<m:items>
<core:Item text="{Name}" />
</m:items>
</m:ComboBox>
</template>
</Column>
Controller: This is the parameterset.
success : function(oData, oResponse) {
// create JSON model
var oODataJSONModel = new sap.ui.model.json.JSONModel();
var child1 = [];
child1.push({Name:"S"});
child1.push({Name:"E"});
oData.Status = child1;
oODataJSONModel.setData(oData);
oView.setModel(oODataJSONModel, "items");
Thanks for helping!

You're missing alias for model in property binding of Item.
<core:Item text="{items>Name}" />

If you want to read the value of the combobox when it changes you can do the following. First in the XML, set the property selectionChange="nameOfYourFunction" in the combobox element. Whenever the user clicks on a different item, nameOfYourFunction() will execute. Here in this function you can check for the value.
nameOfYourFunction : function(){
//Do whatever you want to do here when user changes value of combo
this.getView().byId("combobox_id_here").getValue(); // returns text inside combobox
}
You might have to play around with the function and see when exactly it gets called. I have done a little with it and sometimes it gets called twice. I think once when the Combobox's text is a value in the list and then it gets called again when you leave focus of the combobox. Getting called twice probably won't affect your code though, depends on what you do in your function.

Related

How to synchronize control values within different views

I would like to know how to get the content of TextArea, assign the value to a variable, set it to a model, and then set the variable to another TextArea in another view. I have coded some examples and it works, but not on TextArea.
Here is the example code:
// In init of the Component.js
this.setModel(new JSONModel(), "TransportModel"); // JSONModel required from "sap/ui/model/json/JSONModel"
// In *.controller.js
this.getView().getModel("TransportModel").setProperty("/", {
"Serial": this.byId("mat_serial").getValue() // "mat_serial" == id of the Input box in XML view
});
In the last step, I set the Text from a different View (also XML and Input Box) with the Value of the Model Element.
<Text text="{TransportModel>/Serial}" />
That worked pretty well.
But how to do the same with the TextArea? How can I do it based on this model? The value that I want to use from the first TextArea should also be on a TextArea in another view.
UI5 supports two-way data binding. I.e. if the user changes something in the UI (e.g. user types something in the text area), that change will be reflected automatically in other bindings that listen to the change.
<!-- In view 1 -->
<TextArea value="{TransportModel>/Serial}" />
<!-- In view 2 -->
<Text text="{TransportModel>/Serial}" />
No need to get input values by hand. Simply let the framework synchronize the value.
How to use a local json model:
Create
initItemViewModel: function () {
return new JSONModel({
Serial: ""
});
}
this._oViewModel = this.initItemViewModel();
this.setModel(this._oViewModel, "TransportModel");
Using
this.getView().getModel("TransportModel").setProperty("/Serial", serial);
<Text text="{TransportModel>/Serial}" width="auto" maxLines="1"/>

Event Handler for JSONModel Change?

Say, there's an sap.m.table whose items are bound to a JSON model - "/rows". Outside sap.m.table layout, there's a toolbar that contains "Add" button to add rows to the table. "Add" button adds rows to the table using model's setProperty method. Now, the requirement is to disable "Add" button when JSON model "/rows" length has reached 10. How do we create a handler to observe the changes of JSON model's "/rows" property? https://sapui5.netweaver.ondemand.com/1.52.22/#/api/sap.ui.model.Model/events/propertyChange states that
Currently the event is only fired with reason sap.ui.model.ChangeReason.Binding which is fired when two way changes occur to a value of a property binding.
This means that the eventHandler of propertyChange doesn't get triggered when JSONModel's setProperty() is called. Is there a way out where we can observe the changes of JSONModel's property changes - in this case, "/rows" property of the JSONModel?
Well I can think of several ways to achieve this
1. Standard view binding + formatter:
View
...
<Button text="Add" press="onPressAdd" enabled="{path: '/rows', formatter: '.isAddEnabled'}" />
...
Controller:
Controller.prototype.isAddEnabled = function(rows) {
return rows && rows.length < 10;
}
2. Expression binding (pure xml)
...
<Button text="Add" press="onPressAdd" enabled="{= ${/rows/length} < 10 }" />
...
3. JSONPropertyBinding (pure javascript)
You can call bindProperty on JSONModel to create a property binding that can be observed for changes:
https://sapui5.hana.ondemand.com/#/api/sap.ui.model.Model/methods/bindProperty
https://sapui5.hana.ondemand.com/#/api/sap.ui.model.json.JSONPropertyBinding
Controller.prototype.onInit = function() {
var model = this.getMyJsonModel();
var button = this.getView().byId("myButtonId");
model.bindProperty("/rows").attachChange(function(event) {
button.setEnabled(event.getSource().getValue().length < 10);
})
}

Setting multiple properties of a component with one function

I have a component in a list in a sapui5 XML view and I want to set multiple properties of that component with one function. E.g. I want to set text, status, tooltip and icon of an ObjectStatus together, because the values of those are all different facets of the same data. The issue is that i have to calculate the values to set to those properties from the model with the same relatively time-heavy function. If I write a separate formatter for each of those properties, it has to run the same function for each property. Instead of this I would like to write one function that runs this time-heavy function once and sets a value to all those properties at the same time.
To accomplish this, I have tried creating a sapui5 fragment that could be placed in the list and filled with different information by the createContent function for each instance of that fragment. However I cannot figure out how to do this.
In the view definitions I'm trying to instantiate the fragment like this:
<core:Fragment fragmentName="QuantificationParameter" type="JS" path="{project>}"/>
And then I'm trying to set different content to each instance of the fragment:
sap.ui.jsfragment("namespace.fragments.QuantificationParameter", {
createContent: function(oParentController) {
//Get the object bound to this list item
var derived; //Calculate some intermediate information from this object
return new sap.m.ObjectStatus({
icon: derived.icon,
text: derived.text,
state: derived.state,
tooltip: derived.tooltip
});
}
});
While debugging it seems that the createContent function of the fragment is run only once and I cannot figure out any way to access the data that I'm trying to bind to the fragment. Is there any way I can render different content to each instance of the fragment?
What you are searching for is called databinding.
But first of all: we do not use JS Fragments, due to the same reason we do not use JS views. Here s a little Blog written on that topic.
https://blogs.sap.com/2018/05/01/why-do-we-use-xml-views-rather-js-views-in-sapui5/
Now the databinding part:
I asume, that Fragment will have the same controlls for each instance and you just want the values to change. To do just that you need to create a JSONModel either in your BaseController or component.js. In this Model you store i.e. your Labels text.
Inside your Fragmet you bind that property to the label. Since JSONModels bindingmode is two way by default the Label will change dynamically if you update the model. You can update the model i.e. everytime the user clicks on one of your list items.
Framgmet example:
<core:FragmentDefinition
xmlns="sap.m"
xmlns:f="sap.ui.layout.form"
xmlns:core="sap.ui.core">
<f:SimpleForm
editable="true">
<f:content>
<Input
value="{baseModel>/inputA}"
type="Text"
placeholder="{i18n>placeHolder}"/>
<TextArea
value="{baseModel>/textA}"/>
<TextArea
editable="false"
value="{baseModel>/textB}"/>
</f:content>
</f:SimpleForm>
</core:FragmentDefinition>
creation of the model i.e in component.js:
var oBaseModel = new JSONModel({
inputA: "",
textA: "",
textB: ""
});
this.setModel(oBaseModel, "baseModel");
example for your press lit item funtion:
(should be in the controller of the view your list is located in)
onListPress: function (oEvent) {
var oLine = oEvent.getSource().getBindingContext("yourRemoteService").getObject();
this._oBaseModel.setProperty("/inputA", oLine.ListPropertyA);
this._oBaseModel.setProperty("/textA", oLine.ListPropertyb);
this._oBaseModel.setProperty("/textB", oLine.ListPropertyC);
}
You should really give that tutorial a go:
https://sapui5.hana.ondemand.com/#/topic/e5310932a71f42daa41f3a6143efca9c

Is there an event in sap.m.PlanningCalendar for the rows loaded?

When using the WorkList (and even Master-detail) templates you have the following event in the onInit function:
oTable.attachEventOnce("updateFinished", function() {
// Restore original busy indicator delay for worklist's table
oViewModel.setProperty("/tableBusyDelay", iOriginalBusyDelay);
});
In the view.xml you also have the eventHandler for updateFinished which you can set, so that you are able to do stuff when the data is received in your list.
In the PlanningCalendar you don't have such an eventhandler, how do we handle these kind of things for such a component?
The logic I'm trying to implement is the following:
<PlanningCalendar
id="PC1"
rows="{
path: '/DeveloperSet'
}"
viewKey="Day"
busyIndicatorDelay="{planningView>/calendarBusyDelay}"
noDataText="{planningView>/calendarNoDataText}"
appointmentSelect="onAppointmentSelect"
rowSelectionChange="onDeveloperRowChange"
startDateChange="onStartDateChange">
<toolbarContent>
<Title
text="Title"
titleStyle="H4" />
<ToolbarSpacer />
<Button
id="bLegend"
icon="sap-icon://legend"
type="Transparant"
press="onShowlegend" />
</toolbarContent>
<rows>
<PlanningCalendarRow
icon="{Pic}"
title="{Name}"
text="{Role}" />
</rows>
</PlanningCalendar>
I want to load and add the "appointments" only for the visible part (filter on start and endDate) of the calendar, so I want to perform the oDataModel.read-calls myself. But the rows (the DeveloperSet) should always remain the same. So I should be able to "wait" until the calendar has the data/rows filled in the calendar and then do my manual calls to retrieve the appointments.
So I need to be able to do something when the data is retrieved, but there is no updateFinished event for a calendar?
Does anybody have an idea on how to solve this?
the event "updateFinished" when used in the Table or List is triggered from method updateList, this method handles the update of aggregation "list"
PlanningCalendar does not have an updateRows method, therefore no event "updateFinished"
You could listen to the dataReceived event on the Row binding, if you have one
OnInit: function(){
...
this.oPlanningCalendar = this.byId("PC1")
var oBinding = oPlanningCalendar.getBinding("rows");
oBinding.attachDataReceived(this.fnDataReceived, this);
else you can extend the control and add your own updateRows method and fire "updateFinished", the hack test below shows it would work
OnInit: function(){
...
this.oPlanningCalendar = this.byId("PC1");
this.oPlanningCalendar.updateRows = function(sReason) {
this.oPlanningCalendar.updateAggregation("rows");
var oBinding = this.oPlanningCalendar.getBinding("rows");
if (oBinding) {
jQuery.sap.log.info("max rows = " + oBinding.getLength() || 0);
}
}.bind(this);

I want to use the onSelect event of a ZK tree which is rendered through MVVM

Here is the zul file for reference
<?page title="MVVM Tree POC"?>
<zk>
<borderlayout height="800px">
<west size="25%"></west>
<center>
<window apply="org.zkoss.bind.BindComposer"
viewModel="#id('vm') #init('com.nagarro.viewmodel.TreeViewModel')"
title="Dynamic Tree" border="normal">
<tree checkmark="true" model="#bind(vm.treeModel)"
onSelect="#command('select')" >
<template name="model" var="node" status="s">
<treeitem checkable="#load(node.checkable)"
open="true">
<treerow style="text-align:center;">
<treecell
label="#bind(node.data.firstName)" style="text-align:left;">
</treecell>
</treerow>
</treeitem>
</template>
</tree>
</window>
</center>
</borderlayout>
</zk>
There is a "onSelect" event in the tree tag and there are checkboxes for some treeItems only. Now, I want to create certain components like a combobox for the corresponding tree row when its checkbox is selected. I am trying to do it with the onSelect event of the tree but the problem is I need to pass the reference of the selected checkbox which I am unable to pass as the onSelect event is kept outside the scope of the template through which treeItems are getting rendered.
Is there any other way out to do what I want
This is the page which I get through the above zul file.
I want to know which checkbox is selected ?
You can pass any parameter on every event like that (from ZK docs):
<button label="Delete" onClick="#command('delete', item=item)"/>
and use this parameter in your java code:
#Command
public void delete(#BindingParam("item") Item item ) {
//do some stuff based on what item you've picked
}
In your case I would move onSelect-Event from Tree-Component to Treeitem, like this:
<tree checkmark="true" model="#bind(vm.treeModel)">
<template name="model" var="node" status="s">
<treeitem checkable="#load(node.checkable)"
open="true" onSelect="#command('select', nameParameter=node.data.firstName">
<treerow style="text-align:center;">
<treecell
label="#bind(node.data.firstName)" style="text-align:left;">
</treecell>
</treerow>
</treeitem>
</template>
</tree>
and use parameter in your #Command-method:
#Command
public void select(#BindingParam("nameParameter") String nameParameter ) {
System.out.println(nameParameter + " selected");
}
See ZK MVVM > Advance > Parameter Docs for more information
This is an issue I often run into. My solution has always been to attach data to the component itself; keep a database entity's id or an object itself on the checkbox for retrieval during the event.
checkbox.setAttribute("myAttributeName", myAttributeValue);
This requires a cast to retrieve, which is unfortunate, but with some best practices you can do so confidently.