Display sum of bound numeric values in XML - sapui5

I am using an OData model to bind UI controls with values. I need to sum two values from model values.
<Input id="__input8" class="rt1" value="{D1}" maxLength="1" type="Number" placeholder="" enabled="true" editable="true" />
<Input id="__input9" class="rt1" value="{D2}" maxLength="1" type="Number" placeholder="" enabled="true" editable="true" />
<Text id="__input15" class="rt1" text="{D1} + {D2}" />
I need to sum the D1 and D2 values in the Text control. I am using XML for view and JS for controller.
var oModel = new sap.ui.model.odata.ODataModel(sServiceUrl, true);
var oJsonModel = new sap.ui.model.json.JSONModel();
oModel.read("/xxxSet?", null, null, true, function (oData,repsonse) {
oJsonModel.setData(oData);
});
this.getView().setModel(oModel);
This is my OData connection.

You can use an Expression Binding:
<Text id="__input15" class="rt1" text="{= ${D1} + ${D2}}" />

Nice, finally a post where i can help.
First, i would set a formatter. Since my root usually is sap.ui.app, and my formatter is inside a model folder and called formatter, i can call it like "sap.ui.app.model.formatter"
You can check whats the name of your root inside your index.
data-sap-ui-resourceroots='{"sap.ui.app": "./"}'>
Thats your root. Create a folder inside sap.ui.app named model, and inside the model create a file called formatter.js and inside the file write this code.
jQuery.sap.declare("sap.ui.app.model.formatter");
sap.ui.app.model.formatter =
{
function1: (a, b)
{
return a+b;
}
};
Next, you should call the formatter from your view.
<Text id="__input15" class="rt1" text="{parts:[{path : 'D1'}, {path : 'D2'}], formatter:'sap.ui.app.model.formatter.function1'}" />
Thats it. It should work now.
EDIT: I'm glad my answer helped.

Related

SAP UI5 : Unable to bind a controller variable in xml

Button on click of which the variable is getting changed:
<f:content>
<Button icon="sap-icon://edit" press="editClick" type="Transparent"></Button>
</f:content>
xml code where i need 2-way binding:
<VBox class="sapUiSmallMargin">
<form:SimpleForm id="SimpleFormDisplayColumn_oneGroup">
<form:content>
<Label text="{i18n>contextofusage}"/>
<Text text="{contextofusagetext}" visible="{!isInfoEditable}"/>
<Input type="Text" visible="{isInfoEditable}" value="{contextofusagetext}"></Input>
</form:content>
</form:SimpleForm>
</VBox>
controller:
var isInfoEditable=false;
return Controller.extend("abc.controller.Detail", {
editInfoClick: function(event){
if(isInfoEditable){
isInfoEditable=false;
}
else{
isInfoEditable=true;
}
}
});
It seems like you have tried nothing, but I will try to guide you:
You cannot simply declare a variable in your controller and then use it in your view. That's not how UI5 works. Instead create a model and bind it to your view. I also give my models a name, in this case "view":
onInit: function() {
var oViewModel = new sap.ui.model.json.JSONModel({
isInfoEditable: false
});
this.getView().setModel(oViewModel, "view");
}
Then use it in your view. Make sure that you use the name of your model ("view") in your bindings. If you want to do more than simply use the raw value (e.g. negate it) you have to use expression binding. Also you have to use an absolute path starting with /:
<form:SimpleForm id="SimpleFormDisplayColumn_oneGroup">
<form:content>
<Label text="{i18n>contextofusage}"/>
<Text text="{contextofusagetext}" visible="{= !${view>/isInfoEditable} }"/>
<Input type="Text" visible="{view>/isInfoEditable}" value="{contextofusagetext}"></Input>
</form:content>
</form:SimpleForm>
When you click on the button you have to modify/toggle the value in your model:
editClick: function (oEvent) {
var oViewModel = this.getView().getModel("view");
var bIsEditable = oViewModel.getProperty("/isInfoEditable");
// negate the current value and set it as the new value
oViewModel.setProperty("/isInfoEditable", !bIsEditable);
}
I suggest strongly reading on the basics of UI5. Your approach looks more like Vue.js, but UI5 has its own paradigms.

Input assisted doesn't show all suggestions

I have input field i need suggest items from odata model.
<Input
id="productInput"
type="Text"
placeholder="Enter Product ..."
showSuggestion="true"
showValueHelp="true"
valueHelpRequest="handleValueHelp"
suggestionItems="{/ProductCollection}" >
<suggestionItems>
<core:Item text="{Name}" />
</suggestionItems>
</Input>
the problem is there are missing items : not all items are displayed (you can check this link
https://sapui5.hana.ondemand.com/#/sample/sap.m.sample.InputAssisted/preview
it is the same behaviour when you put a for example it shows some items in the search it shows more with a )
What you are trying to do is basically show all items that contains the value in the input. SAPUI5 has a convenient filter for this called sap.ui.model.FilterOperator.Contains.
The problem with the sap.m.Input is that it will only work one way, even if you manually set the Contains filter in the Suggest event, it will show suggestions that will start with the provided letter instead, just like sap.ui.model.FilterOperator.StartsWith filter operator. That's why it is showing you less suggestions.
Using the same products.json model in your question, we can do the following:
XML Input:
<Label text="Product" labelFor="productInput"/>
<Input
id="productInput"
type="Text"
placeholder="Enter Product ..."
showSuggestion="true"
showValueHelp="false"
suggest="handleSuggest"
suggestionItems="{productsModel>/ProductCollection}" >
<suggestionItems>
<core:Item text="{productsModel>Name}" />
</suggestionItems>
</Input>
Controller:
handleSuggest: function (oEvent) {
var aFilters = [];
var sTerm = oEvent.getParameter("suggestValue");
if (sTerm) {
aFilters.push(new sap.ui.model.Filter("Name", sap.ui.model.FilterOperator.Contains, sTerm));
}
oEvent.getSource().getBinding("suggestionItems").filter(aFilters);
//do not filter the provided suggestions before showing them to the user - important
oEvent.getSource().setFilterSuggests(false);
}
It is very important to set the setFilterSuggests() method to false in order not to filter the provided suggestions before showing them to the user, this would go against we just did previously.
Using this approach, the suggested item will show only those values filtered by the specified filter condition which is sap.ui.model.FilterOperator.Contains.
Other SAPUI5 Filter Operators

Data Binding from TableSelectDialog to Form

I'm using TableSelectDialog to view some Carrier details. All I need is: If I select any item (row), then all the values from that row should get automatically populated to the form input fields.
In the attached image, if Carrier Name is selected from TableSelectDialog, then the remaining fields should be populated based on that value.
You can achieve the required functionality using the Binding context that you receive from the TableSelcect Dialog.
But for binding context to work properly, both form and the table select dialog should refer to the same Model.
Below is the working code:
VIEW.XML:
Has a Button to trigger the table select dialog.
Has a form.
<l:VerticalLayout class="sapUiContentPadding" width="100%">
<l:content>
<Button class="sapUiSmallMarginBottom" text="Show Table Select Dialog"
press="handleTableSelectDialogPress">
</Button>
<VBox class="sapUiSmallMargin">
<f:SimpleForm id="SimpleFormDisplay354">
<f:content>
<Label text="Supplier Name" />
<Text id="nameText" text="{SupplierName}" />
<Label text="Description" />
<Text text="{Description}" />
<Label text="ProductId" />
<Text text="{ProductId}" />
<Label text="Quantity" />
<Text id="countryText" text="{Quantity}" />
</f:content>
</f:SimpleForm>
</VBox>
</l:content>
</l:VerticalLayout>
Controller:
onInit: function () {
// set explored app's demo model on this sample
var oModel = new JSONModel(jQuery.sap.getModulePath("sap.ui.demo.mock", "/products.json"));
this.getView().setModel(oModel);
},
handleTableSelectDialogPress: function (oEvent) {
if (!this._oDialog) {
this._oDialog = sap.ui.xmlfragment("sap.m.sample.TableSelectDialog.Dialog", this);
}
this.getView().addDependent(this._oDialog);
// toggle compact style
this._oDialog.open();
},
handleClose: function (oEvent) {
var aContexts = oEvent.getParameter("selectedContexts");
if (aContexts && aContexts.length) {
// MessageToast.show("You have chosen " + aContexts.map(function(oContext) { return oContext.getObject().Name; }).join(", "));
this.byId('SimpleFormDisplay354').setBindingContext(aContexts[0]);
}
oEvent.getSource().getBinding("items").filter([]);
}
Now, we also have a Select dialog and on click of any Item we call method : handleClose
In handleClose, we obtain the clicked Item binding context and then tell the form : hey! refer to this context ( which is present in the model). Binding context has a path which tells the form from where to do the relative binding.
Please feel free to contact for more information.

Attach browser event to a control using XML-View

My REST service send me a lot of data. Every property contains the value and a help-attribute that contains a long description of the field property.
Ok, I have data (a list of property with value and help) in a JSONModel and I use data-binding XML https://openui5.hana.ondemand.com/#docs/guide/91f0f3cd6f4d1014b6dd926db0e91070.html to map data value in forms and tables.
Now I want show somehow help message for each property.
My idea is show a message dialog when the user double-click on the Label or on the Text of the column header in a table
Both Label and Text have attachBrowserEvent method but I don't know how use the function to attach the event wrinting only in the XML-views
I would like something like this:
In XML-View:
<Label text="Language"
attachBrowserEvent:"function("click",showMessageHelp({model>/language/help}))">
<Input value="{model>/language/value}"/>
In the controller:
showMessageHelp:function(sMessage){
//show message dialog with sMessage
...........
}
You can achieve this using onAfterRendering method.
Have CustomData in the XML:
<Label id="label" text="Language">
<customData>
<core:CustomData key="type" value="{/language/help}" />
</customData>
</Label>
Then in controller use this customData:
onAfterRendering: function () {
var showValueHelp = function () {
var text = this.getCustomData()[0].getValue();
sap.m.MessageToast.show(text);
event.preventDefault();
event.stopPropagation();
return false;
};
this.byId("label").attachBrowserEvent("click", showValueHelp);
}
JS fiddle is here
PS:I am not sure this is viable solution for you.
This is the best I could come up with, currently.
Attach a browser event for each label is possible but I can't find a way to do it without repeat each label id.
I have found an alternative solution: my data are shown in forms and tables.
I have added on the right of each form couple of label: value a Text element with the help info:
<Label text="Field duck"/>
<Text text="{model>/elements/mainFields1/duck/value}"/>
<Text text="{model>/elements/mainFields1/duck/ATTR/help/description}" visible="{ui>/bShowHelp}" />
In tables I have divided each column title in two group: header and footer; in the footer I have placed the help info:
<Column>
<header>
<Text text="Name"/>
</header>
<footer>
<Text text="{model>/elements/airports/templateNewRow/name/ATTR/help/description}" visible="{ui>/bShowHelp}"/>
</footer>
</Column>
I change the value of bShowHelp showing and hiding all help infos

How to dynamically load an XML fragment in XML view?

Suppose I have the following XML view:
<mvc:View xmlns:mvc="sap.ui.core.mvc" ...>
<Page>
<content>
<l:VerticalLayout>
<l:content>
<core:Fragment fragmentName="my.static.Fragment" type="XML" />
</l:content>
</l:VerticalLayout>
</content>
</Page>
</mvc:View>
The fragment my.Fragment is statically loaded. However, I now want to dynamically change the to-be-loaded fragment (ideally using data binding the fragmentName property, but any other means should be ok as well), ie. something like this:
<mvc:View xmlns:core="sap.ui.core.mvc" ...>
<Page>
<content>
<l:VerticalLayout>
<l:content>
<core:Fragment fragmentName="{/myDynamicFragment}" type="XML" />
</l:content>
</l:VerticalLayout>
</content>
</Page>
</mvc:View>
However, the latter does not work, and the Fragment definitions don't allow for data binding... I might have missed something, but how should I dynamically change the Fragment in my XML view based on a parameter/model property/etc?
For now, I have resorted to a custom control instead of directly using a fragment in my view, and have that control do the dispatching to the appropriate Fragment, but I feel there should be an easier, out-of-the-box way...
I think the only solution will be initialization of fragment from onInit method of controller:
sap.ui.controller("my.controller", {
onInit : function(){
var oLayout = this.getView().byId('mainLayout'), //don't forget to set id for a VerticalLayout
oFragment = sap.ui.xmlfragment(this.fragmentName.bind(this));
oLayout.addContent(oFragment);
},
fragmentName : function(){
return "my.fragment";
}
});
The fragment name can also result from a binding, including an expression binding which evaluates to a constant. As formatter functions return strings, and not booleans, === 'true' has been added in the following example:
Example: Dynamic Fragment Name
<core:Fragment fragmentName="{= ${path: 'facet>Target', formatter: 'sap.ui.model.odata.AnnotationHelper.isMultiple'} === 'true'
? 'sap.ui.core.sample.ViewTemplate.scenario.TableFacet'
: 'sap.ui.core.sample.ViewTemplate.scenario.FormFacet' }" type="XML"/>