I have a very strange issue with formatter function.
I have the following formatter:
_formatter: function(sAccessLevel){
switch(sAccessLevel){
case "fullAccess":
return true;
case "readOnly":
return false;
case "norefund":
return false;
case "nodiscount":
return false;
default:
return false;
}
},
for the following field:
<Column visible="{path: 'modelName>/Access', formatter: '_formatter'}" >
<header hAlign="Middle" vAlign="Middle">
<Text text="{i18n>discount}" textAlign="Center"/>
</header>
</Column>
And in try-catch block I sometimes get the following error:
Error: "nodiscount" is of type string, expected boolean for property "visible" of Element sap.m.Column#__column154
or
Error: "fullAccess" is of type string, expected boolean for property "visible" of Element sap.m.Column#__column489
When I try to reproduce the error, the code works fine, but in production system's log I see the above error.
How this error possible?
Thank you.
Its a simple mistake. While giving the formatter in XML view we have to give the .formatterFunctionName as below.
<Column visible="{path: 'modelName>/Access', formatter: '._formatter'}" >
<header hAlign="Middle" vAlign="Middle">
<Text text="{i18n>discount}" textAlign="Center"/>
</header>
</Column>
In the controller implement your formatter function as usual.
Related
Hello dear colleagues,
I want to bold the total line and set highlight to red.
I am using the event modelContextChange:
<ColumnListItem vAlign="Middle" modelContextChange="onModelContextChange">
<cells>
<!--<ObjectIdentifier title="{Name}" text="{year}"/>
<Text text="{month}"/>-->
<Text text="{salesOrganization}" modelContextChange="onTextContextChange" />
<Text text="{product}" />
The event code:
onModelContextChange: function (oEvent) {
debugger
var oListItems = oEvent.getSource();
var oObject = oListItems.getBindingContext().getObject();
if (oObject.salesOrganization === "Total") {
// debugger
oListItems.setHighlight("Error");
// oText.addStyleClass("boldText");
} else {
oListItems.setHighlight("Information");
}
},
The issue with this approach is that when the context does not change the Highlight does not work properly. I´ve tried using custom formatted, but I could not make it work. Also, I could not find a way to read the row value to do the same logic above.
Would you give me any hint on how achieve it?
Thanks a lot
Pietro
View:
<Table mode="SingleSelectMaster" select="selectItem">
Controller:
selectItem: function(oEvent){
const oSelectedItem = oEvent.getSource().getSelectedItem();
oEvent.getSource().getItems().forEach(oItem => oItem.removeStyleClass("boldText")); //Remove bold class from all items
oSelectedItem.addStyleClass("boldText"); //Add class to selected item
},
CSS:
.boldText>td>span{
font-weight: bold !important;
}
I have a column in table whose value is bound to a property of data model.
text = { modelName>/OrderNo}. How to make it conditional based on a flag? If property from Model isReturnable = true, I want to show text = {modelName>/ReturnNo} else I want to show {OrderNo}. How to built syntax for that?
<table:Column>
<Label class="smartist-table-column-header" text="Qty Returned"/>
<table:template>
<Text text="{ path: 'OrderDetail>OrderNo'}"/>
</table:template>
</table:Column>
You can use expression binding.
See URL for details: https://ui5.sap.com/#/topic/daf6852a04b44d118963968a1239d2c0
Solution to your problem:
<Text text="{= ${modelName>isReturnable} ? ${modelName>/ReturnNo} : ${OrderDetail>OrderNo}}" />
As expression binding would be a more appropriate approach to this problem,
Custom formatting can also be one way to achieve this.
In the view:
<Text text= "{ parts:[
{path: "modelName>isReturnable"},
{path: "modelName>ReturnNo"},
{path: "modelName>OrderNo"},
],
formatter: '.formatOrderNo'
}"/>
In the corresponding controller
formatter: function(isReturnable, sReturnNo, sOrderNo){
if(isReturnable == true){
return sReturnNo;
}else{
return OrderNo;
}
}
In case of more complex logic where you need to perform some calculations/manipulations on the fields before binding, custom formatting is the way to go. Custom Formatters in SAPUI5
I am adding controls to SAPUI5 table column items via the controller using factory function so that I can apply cross-field validation along with standard control validations. Now the validation is working fine it shows the error message with the red coloured border, but when I move to next control, validation state of control disappear. I noticed that it is happening due to some internal functionality of SAPUI5 where it re-render the table body element of the table in the HTML dom explorer which also get rid of the error classes applied to control. It occurs for the first time, but when I try to change the value again of the same controller with an invalid data, it displays the error and keeps the value state with the red border.
my table XML view
<Table id="todosTable" growing="true" items="{
path: 'TripService>/todos', factory: '.populateItems'
}">
<columns>
<Column id="id">
<Text text="Id"/>
</Column>
<Column id="title">
<Text text="Title"/>
</Column>
<Column id="url">
<Text text="Url"/>
</Column>
<Column id="thumbnailUrl">
<Text text="Thumbnail Url"/>
</Column>
</columns>
</Table>
My Controller code to apply the columns item
function populateItems(sId: any, oContext: any) {
const idInput = new Input({
value: "{TripService>id}",
id: `id_${sId}`,
liveChange: onIdChange.bind(this)
});
const titleInput = new Input({
value: "{TripService>title}",
id: `title_${sId}`,
liveChange: onTitleChange.bind(this)
});
const urlInput = new Input({
value: "{TripService>url}"
});
const tumbnailInput = new Input({
value: "{TripService>thumbnailUrl}"
});
var row = new ColumnListItem(sId, {
cells: [idInput, titleInput, urlInput, tumbnailInput]
});
return row;
}
function onIdChange(oEvent: any) {
oEvent.oSource.setValueState(sap.ui.core.ValueState.Error);
}
function onTitleChange(oEvent: any) {
oEvent.oSource.setValueState(sap.ui.core.ValueState.Error);
}
Some images with valid error state and then with buggy error state
As you can see in above two images the error is gone in second image though I expect it to be there.
I try to format the visibility property according to a custom parameter.
Element definition in the view:
<CheckBox id="compensation0" selected="false" enabled="true"
visible="{formatter: 'my.util.Formatter.visible'}" editable="true" select=""/>
Formatter:
my.util.Formatter = {
visible: function(){
return true;
}
};
The error I get:
UIComponent.js:6 Uncaught Error: "[object Object]" is of type object,
expected boolean for property "visible" of
Element sap.m.CheckBox #__xmlview1--compensationColumn
What did I do wrong?
Thank you.
I am not entirely sure, but shouldn't the formatter expect also a path property (despite if you use it or not)?
Also, I would have expected your formatter to be written in AMD structure:
sap.ui.define([], function () {
"use strict";
return {
visible: function(value) {
return true;
}
};
});
BindingParser fails since you do not have a path property at your binding object definition. At the end you have an object for the boolean visible property which is invalid.
Your definition of the CheckBox contain errors: Try it in this way:
<CheckBox id="compensation0" selected="false" enabled="true"
visible="{path: '', formatter: 'my.util.Formatter.visible'}" editable="true" select=""/>
In SAPUI5's JSView, it is quite easy to pass the current control reference to a formatter function:
oTable.bindItems("/rows", new sap.m.ColumnListItem({
cells : [ new sap.m.Text().bindProperty("text", {
parts: [
{ path: "someInteger" }
],
formatter: function(iValue) {
var idText = this.getId(); //this references the current control
return iValue;
}
})]
}));
(The 'easy' part of course is because this is referenced in the control's inner formatter function)
However, with XMLViews I haven't managed yet to get a reference to the current control in the formatter function:
<Table items="{/rows}">
<columns>
<Column>
<Text text="Some Integer" />
</Column>
</columns>
<items>
<ColumnListItem>
<cells>
<Text text="{ path : 'someInteger', formatter : '.formatCell' }" />
</cells>
</ColumnListItem>
</items>
</Table>
And the formatter:
formatCell : function (sValue) {
var a = this; //this references the controller
return sValue;
}
Anyone knows how to make this work in XMLViews?
Define your formatter functions in a separate file. Then this will be the Control whose property is being formatted.
my/own/Formatter.js:
sap.ui.define(function () {
"use strict";
return {
formatCell: function (iValue) {
var idText = this.getId(); //this references the current control
return iValue;
}
};
});
View:
<Table items="{/rows}">
<columns>
<Column>
<Text text="Some Integer" />
</Column>
</columns>
<items>
<ColumnListItem>
<cells>
<Text text="{ path : 'someInteger', formatter : 'my.own.Formatter.formatCell' }" />
</cells>
</ColumnListItem>
</items>
</Table>
The answer of #codeworrior in this issue make it more clear:
A name that starts with a dot (e.g. ".foo") is searched for in the controller of the view and the execution context will be enforced to being the controller.
All other names are resolved starting from the window object and they get the control/element as context which holds the binding.
Just complement #hirse's answer, and for those who get formatter function xxx not found error:
both .formatter.myformatter and mynamespace.Formatter.myformatter is working.
The logic of parse formatter is in sap.ui.base.BindingParser.resolveRef(oBindingInfo,'formatter')
BindingParser seems different in sapUI5(1.54) and openUI5. I'll take sapUI5 version as an example.
If formatter name starts with a dot ('.'), eg. .formatter.myformatter, lookup will start with the given context(the Controller of the view), otherwise("mynamespace.Formatter.myformatter") it will start with the global context (window).
and jQuery.sap.getObject("formatter.myformatter", oContext) or jQuery.sap.getObject("mynamespace.Formatter.myformatter", window) is called.
so If you get formatter function xxx not found! error. set a break point in jQuery.sap.getObject, and check if there is "myformatter" in oContext or window object.
And I found that there is no mynamespace.Formatter.myformatter in my window object. so I change my formatter from
sap.ui.define([], function() {
return {
myformatter: function () {}
}
})
To
sap.ui.define([], function() {
var Formatter = {
myformatter: function () {}
}
return Formatter
}, /* bExport */ true)
And it's working.
Formatter must be defined with variable. Formatter reference must be included in controller. Formatter must be referenced with absolut path.
Formatter.js
sap.ui.define([], function () {
var Formatter = {
myFormatter: function () {
return "";
}
}
return Formatter }, /* bExport */ true)
View.controller.js
sap.ui.define([
...
"com/my/company/utils/Formatter"], function (..., Formatter) {
"use strict";
return Controller.extend("com.my.company.View", {
View.view.xml
<GenericTag status="{path: 'MyStatus', formatter: 'com.my.company.utils.Formatter.myFormatter'}/>