SAP / openui5

OpenUI5 lets you build enterprise-ready web applications, responsive to all devices, running on almost any browser of your choice.
http://openui5.org
Apache License 2.0
2.94k stars 1.23k forks source link

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

Open DerGuteWolf opened 8 years ago

DerGuteWolf commented 8 years ago

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}' }] }">

ie use a binding for the value1 field of the filter.

aborjinik commented 8 years ago

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.

DerGuteWolf commented 8 years ago

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?

ThomasChadzelek commented 8 years ago

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 }

LukasHeimann commented 3 years ago

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

ThomasChadzelek commented 3 years ago

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

LukasHeimann commented 3 years ago

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 :/