Openui5: Unable to get reference to the element which needs format in xml view

Created on 15 Mar 2016  路  9Comments  路  Source: SAP/openui5

OpenUI5 version: all

Steps to reproduce the problem:

  1. in xml view, define a formatter to the binding of a property or specify a event handler on an event of the element
  2. in the formatter or event handler, there's no way to know which element triggers the function, because the context object is always the controller

What is the expected result?
there should be a way to get the reference to the UI element

consulting

Most helpful comment

Formatters are not event handlers. The documentation in the developer guide, that @hatelove85911 referenced above, is true for event handlers. But for formatters it doesn't apply. Their context depends on the syntax of the name that is specified in the binding:

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 ("nl.qualiture.formatter.formatter.formatCell" in @qualiture's example) and they get the control/element as context which holds the binding.

The reason for the controller formatters being handled differently is a) consistency with the controller event handlers and b) to allow them to access other helpers or data from the controller instance.

Addressing a formatter via a global name instead of via controller local name is the easiest way to get access to the control. Polluting the controller with control specific formatters also would be a technical solution, but I guess it is feasible only in rare cases (e.g. formatter is used only once in the view).

There is already an internal ticket that tracks the lack of proper documentation reg. this: 1570822965.

All 9 comments

@hatelove85911 If you define your formatter in a separate file, this will refer to the control being formatted

@qualiture I did, I defined a formatter in util/formatter.js, but that won't work, in the formatter, this always points to the controller, it's documented in the developer guide->Essentials->Model view controller->views->implementing xml views->Handling Events in XML Views . So there's no option to say I want the context object of format function to be the control.

Not sure what goes wrong then... See this working example: http://plnkr.co/edit/ifqIStF1AY4akC8IpCSD?p=preview. The code in the formatter:

formatCell : function (sValue) {
    this.addStyleClass("myCellStyle1");
    return sValue;
}

adds a style to this (in this case, the sap.m.Text element being formatted, and not the controller), and returns the value as-is

Formatters are not event handlers. The documentation in the developer guide, that @hatelove85911 referenced above, is true for event handlers. But for formatters it doesn't apply. Their context depends on the syntax of the name that is specified in the binding:

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 ("nl.qualiture.formatter.formatter.formatCell" in @qualiture's example) and they get the control/element as context which holds the binding.

The reason for the controller formatters being handled differently is a) consistency with the controller event handlers and b) to allow them to access other helpers or data from the controller instance.

Addressing a formatter via a global name instead of via controller local name is the easiest way to get access to the control. Polluting the controller with control specific formatters also would be a technical solution, but I guess it is feasible only in rare cases (e.g. formatter is used only once in the view).

There is already an internal ticket that tracks the lack of proper documentation reg. this: 1570822965.

@qualiture @codeworrior, thanks for your reply, it clears the doubt I have. The initial problem I has is: I don't remember exactly which part of the developer guide I followed, I created the formatter in AMD fashion in a separate file and I add a "formatter" property to the controller and it's assigned as the formatter module which is required in sap.ui.define. So in the xml view, I refer to the formatter function as
.formatter.xxx, see below. Now in the formatter function, the context object is always the controller. Because I didn't refer to it with global name.
aaaa

===== divider =======================================================
But I run into another stupid awkward issue, what I want:

  1. xml view, because it's clean and declarative
  2. the formatter function can have the reference of the control as context object

The above 2 points lead to a stupid situation:

  1. because I want xml view, the only way to make formatter function has the context object of the control is referring to the formatter function with global name
  2. to refer to the formatter function with global name, I need to have the formatter module loaded before the control needs format.
  3. stupidest thing ever is if I use AMD module definition, there no way to load my formatter into the global namespace
    a. it doesn't work if you define the formatter as a dependency for the controller
    b. it doesn't work if you use jQuery.sap.require to load the AMD module synchronously
  4. as a result, I need to change how I define my formatter from AMD to jQuery.sap.declare, if my formatter has other dependencies, I have to change them too!...

You IMHO could

  • declare a dependency (preferably AMD style) from the controller to the formatter util
  • implement the formatter util as a module (also in AMD style), BUT
  • also export the function or util under a global name:
sap.ui.define([....], function() {
   var MyUtil = {
       myformatter : function(v) {
         return this.getId() + v;
       }
    };

    // export formatter under a global name
    // for hierarchical names you might use jQuery.sap.setObject("name", myformatter)
    window.myformatter = MyUtil.myformatter;

    // standard AMD Style module value
    return MyUtil;

});

As the controller is loaded by the view before bindings can be resolved, any dependency should be loaded in time. Also the global name for the formatter should be established in time then.

However, I must admit that this is not a perfect solution as AMD and the use of global names don't really fit together. We already discussed some months ago the idea of allowing dependency declarations ("requires") in the XML view (similar to namespace definitions). They could introduce shortcuts names that would be evaluated when resolving event handlers, formatters etc. But so far this idea didn't make it into our backlog.

great solution, thanks!

I was facing this particular issue and finally came across this post. Thanks first of all for the solution. But how do we get to know about all these in the first place so that these type of issue don't arise.

Was this page helpful?
0 / 5 - 0 ratings