3

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?

Qualiture
  • 4,900
  • 7
  • 27
  • 38
  • Does this answer your question? [How to have control instance as "this" in formatter?](https://stackoverflow.com/questions/54290194/how-to-have-control-instance-as-this-in-formatter) – Boghyon Hoffmann Apr 04 '20 at 22:44
  • Sorry, trying to guide other readers [again](https://stackoverflow.com/questions/26295695/odatamodel-aggregations-getbindingcontext-returns-undefined#comment86083887_26295695) to (IMHO) better answer :P – Boghyon Hoffmann Apr 04 '20 at 22:44
  • As my original question is almost 5 years old and UI5 has changed significantly over the years, yes, definitely :-) – Qualiture Apr 04 '20 at 22:48

3 Answers3

5

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>
hirse
  • 2,394
  • 1
  • 22
  • 24
  • 4
    I can't get it to work, in the guide it says to include the formatter in the controller and to set ``formatter: Formatter`` in the controller. After that, I can use .formatter in the xml view to call the formatter function. But there it has the view scope, not the scope of the element. Any idea why? – Michael K. Feb 02 '16 at 14:22
  • @MichaelK. The formatter module needs to be exported so that it can be globally referenced by the module name. See https://stackoverflow.com/a/54419469/5846045 – Boghyon Hoffmann Feb 04 '19 at 07:40
2

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.

Community
  • 1
  • 1
Tina Chen
  • 2,010
  • 5
  • 41
  • 73
  • 1
    Thank you for your analysis. About the "`BindingParser` seems different in [sapUI5(1.54)](https://sapui5.hana.ondemand.com/resources/sap/ui/base/BindingParser-dbg.js) and [openUI5](https://github.com/SAP/openui5/blob/f76d2efea1b2099680e0649c19e6024b4ec02876/src/sap.ui.core/src/sap/ui/base/BindingParser.js#L164)": The latter link shows the nightly version (master branch) which has received several updates since the current stable version (1.54). – Boghyon Hoffmann Jun 29 '18 at 21:39
0

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'}/>
Jan Koester
  • 1,178
  • 12
  • 26