openui5 icon indicating copy to clipboard operation
openui5 copied to clipboard

Please allow dynamic fields in filters in extended syntax for aggregation binding in xml views

Open DerGuteWolf opened this issue 10 years ago • 9 comments

This is an enhancement request

I want to do something like this: <Select items="{ path: 'AssignmentSet', sorter: { path: 'Description' }, filters: [{ path: 'ResourceKey', operator: 'NE', value1: '{/Me(1)/Resource/ResourceKey}' }] }"> <core:Item key="{ProductId}" text="{Name}" /> </Select> ie use a binding for the value1 field of the filter.

DerGuteWolf avatar Oct 22 '15 14:10 DerGuteWolf

Hi DerGuteWolf, bindable filter values has been asked several times but this needs a huge architectural change in the framework an binding handling. Anyway, I inform product owner for this enhancement.

aborjinik avatar Oct 23 '15 10:10 aborjinik

Yes, I understand this, as it would introduce a dependency of bindings among each other.

In my specific case, evaluating the value binding once would be ok, can I achieve my goal then somehow with templating?

DerGuteWolf avatar Oct 23 '15 11:10 DerGuteWolf

Yes, you can do this with XML templating, but you need to be careful. Your expression binding must only rely on models available at templating time. The expression should be some string concatenation producing another binding which only relates to "runtime" models. This nesting is a bit tricky. It will soon be documented, here's a preview:

Sometimes one would like to mix both runtime and meta data within a single binding as follows:

Expression Binding With Runtime And Meta Data

{= ${runtime>value} > ${meta>threshold} }

This will not work. XML templating cannot replace this binding because it refers to "runtime", which is not available at that point in time. (We assume "runtime" is the name of the model at runtime. Typically, this would be the default model and have no name, but for clarity we added one here.) Later on, "meta" is not available anymore and this binding cannot work as expected, although it will repeatedly be evaluated (whenever the value changes) and compare the value to undefined. The solution is to have a clear separation here: one expression binding which refers to meta data only and can be replaced by XML templating, another expression binding which referes to runtime data only and can be evaluated later on. The problem is that these two bindings need to be nested. Here's how:

Expression Binding With Meta Data Only

{= '{= ${runtime>value} > ' + ${meta>threshold} + ' }' }

This will be replaced by XML templating with something like the following, which is kind of a partial evaluation of the original mixed binding. By carefully putting pieces into string literals and taking care of escaping you have full control over this process of partial evaluation. We have assumed the threshold value to be a number here, see below for examples with string values.

Expression Binding With Runtime Data Only

{= ${runtime>value} > 42 }

More Examples

Escaping For String Constants

{= '{= '' + ${meta>A} + '' + ${/B} }' } // --> {= 'A' + ${/B} }

Using AnnotationHelper

{= '{= $' + ${path : 'meta>value, formatter : 'sap.ui.model.odata.AnnotationHelper.format'} + ' > ' + ${path : 'meta>threshold', formatter : 'sap.ui.model.odata.AnnotationHelper.format'} + ' }' }

// --> {= ${path : 'path/to/property/value', type : 'sap.ui.model.odata.type.Int16'} > 42 }

ThomasChadzelek avatar Oct 23 '15 18:10 ThomasChadzelek

Hi everyone,

I'm searching for a similar feature and found this issue. Has there been any progress on this?

My initial use case builds on filters only: I have an OData v4 Model I want to filter based on a value I could read from a property of another model (most likely a plain JSON Model):

<core:FragmentDefinition xmlns:core="sap.ui.core">
    <SomeListControl content="{
        path: 'myAssociation',
        filters: [{
            path: 'locale',
            operator: 'EQ',
            value1: { path: 'othermodel>/userLocale' }
        }]
        templateShareable: false }"
    >
        <SomeItemControl text="{name}" />
    </SomeListControl>
</core:FragmentDefinition>

Obviously, today this wouldn't work, as value1 must be a value, as far as I understood the documentation (https://ui5.sap.com/#/topic/5338bd1f9afb45fb8b2af957c3530e8f)

Kind regards Lukas

LukasHeimann avatar Dec 10 '20 09:12 LukasHeimann

Hello @LukasHeimann !

I cannot speak for the PO here, but I would not expect a general feature for "bindable filter values" anytime soon.

For you use case, I would assume that the user locale is constant for your session. You could move the filter from the XML view to your controller code, where you can easily pass that user locale as "value1". I agree that is has downsides, but it is a workaround. What do you think?

Best regards, Thomas

ThomasChadzelek avatar Dec 10 '20 09:12 ThomasChadzelek

Yeah, that's most probably true.

The problem is: this whole thing runs in the context of a Fiori Elements Breakout for a column in a table, so I don't have a real controller.

I could add a function that tries to get the binding and adds the filter to it, but I'd need to find a suitable event triggered by the Control when binding the Aggregation in order to do so -- the ones that do exist sound not right: https://ui5.sap.com/#/api/sap.ui.core.Control%23events/Summary

Something like onBindContent, with oEvent passed to it allowing to get the binding (worst case: oEvent.getSource().getBinding()).

<core:FragmentDefinition xmlns:core="sap.ui.core">
    <SomeListControl
        content="{ path: 'myAssociation', templateShareable: false }"
        core:require="{CustomHandler: 'my/custom/handler'}"
        onBindContent="CustomHandler.onBindContent">
        <SomeItemControl text="{name}" />
    </SomeListControl>
</core:FragmentDefinition>
sap.ui.define(['sap/ui/model/Filter'], function(Filter) {
    return {
        onBindContent: function(oEvent) {
            oEvent.getSource().getBinding().filter(new Filter(/*...*/));
        }
    };
});

But I assume this isn't available as well :/

LukasHeimann avatar Dec 10 '20 10:12 LukasHeimann

@DerGuteWolf @LukasHeimann

In my specific case, evaluating the value binding once would be ok

I'd need to find a suitable event triggered by the Control when binding the Aggregation

<SomeListControl items="{
  path: 'myAssociation',
  filters: '.createFilters',
  templateShareable: false
}">

In the above case, createFilters returning either an array of filters or a single Filter instance would add a $filter queriy to the request URL accordingly. While the new syntax is not supported yet, would that resolve the issue here?

boghyon avatar Aug 05 '25 10:08 boghyon

I moved on to a different project since and can't find the specific requirement and where in the code it relates now. I assume it is not needed anymore.

Not sure if @DerGuteWolf has some additional input

LukasHeimann avatar Aug 05 '25 11:08 LukasHeimann

@boghyon Yes, IMHO this will resolve the issue. Also I solved this originally indeed by XML templating as suggested by @ThomasChadzelek .

DerGuteWolf avatar Aug 06 '25 08:08 DerGuteWolf