Skip to content

Files

Latest commit

 

History

History
344 lines (251 loc) · 13.8 KB

property-binding-91f0652.md

File metadata and controls

344 lines (251 loc) · 13.8 KB

Property Binding

With property binding, you can initialize properties of a control automatically and update them based on the data of the model.

To define property binding on a control, you have the following options:

  • As part of the control's declaration in an XML view

  • Using JavaScript, in the settings object in the constructor of a control, or in special cases, using the bindProperty method of a control

Once you have defined the property binding, the property is updated automatically every time the property value of the bound model is changed, and vice versa.

Let's say, we have the following JSON data:

{
    "company": {
        "name": "Acme Inc.",
        "street": "23 Franklin St.",
        "city": "Claremont",
        "state": "New Hampshire",
        "zip": "03301",
        "revenue": "1833990"
    }
}

To define property binding in the control declaration in the XML view, just include the binding path within curly brackets (see also Binding Path):

<mvc:View 
    controllerName="sap.ui.sample.App"
    xmlns="sap.m"
    xmlns:mvc="sap.ui.core.mvc">
    <Input value="{/company/name}"/>
</mvc:View>

In JavaScript, you can include the binding path within curly brackets as a string literal in the settings object:

// "Input" required from module "sap/m/Input"
const oInput = new Input({value: "{/company/name}"});

You can also use a complex syntax for property bindings. This complex syntax allows you to define additional binding information to be contained in the settings object, such as a formatter function.

You can then set the bindingMode or other additional properties like this:

<mvc:View
    controllerName="sap.ui.sample.App"
    xmlns="sap.m"
    xmlns:mvc="sap.ui.core.mvc">
    <Input value="{path: '/company/name', mode: 'OneWay'}"/>
</mvc:View>

In JavaScript views or controllers, you use a JS object instead of a string literal. This must contain a path property containing the binding path, and can contain additional properties:

// "Input" required from module "sap/m/Input"
// "BindingMode" required from module "sap/ui/model/BindingMode"

const oInput = new Input ({
    value: {
        path: "/company/name",
        mode: BindingMode.OneWay
    }
});

Depending on the use case, it may be useful to define the binding at a later time, using the bindProperty method:

oInput.bindProperty("value", "/company/name");

This option also allows you to use the same object literal that you used in the constructor to define the binding:

// "Integer" required from module "sap/ui/model/type/Integer"

oInput.bindProperty("value", {path: "/company/name", type: Integer});

Note:

Some controls offer convenience methods for their main properties that are most likely to be bound by an application:

oTextField.bindValue("/company/name");

To remove a property binding, you can use the unbindProperty method. The property binding is removed automatically whenever a control is destroyed:

oTextField.unbindProperty("value");

You can also bind multiple paths by combining them as parts of a binding. For more information, see Composite Binding.

Values in data are often represented in an internal format and need to be converted to an external format for visual representation, especially numbers, dates, and times with locale-dependent external formats. OpenUI5 provides two different options for converting data. You can use both options for each binding, you don't have to use one option consistently throughout your app:

  • Formatter functions for one-way conversion

  • Data types in two-way binding

    Data types can be used to parse user input in addition to formatting values.

Using a Formatter Function

If you define the property binding in the XML view, you need to define a formatter function (roundToMillion) in the view controller:

sap.ui.define([
    "sap/ui/core/mvc/Controller",
    "sap/ui/model/json/JSONModel"
], function (Controller, JSONModel) {
    "use strict";

    return Controller.extend("sap.ui.sample.App", {
        roundToMillion(fValue) {
            return `> ${fValue ? Math.floor(fValue / 1000000) : 0} M`;
        }
    });
}); 

The this context of a formatter function is generally set to the control (or managed object) that owns the binding. In XML views, however, the view should contain a reference to the formatter function, which resides in the view controller. This is done by putting a dot (.) in front of the name of the formatter function ({ formatter: '.myformatter' }). In this case, the formatter's this context is bound to the controller.

<mvc:View
    controllerName="sap.ui.sample.App"
    xmlns="sap.m"
    xmlns:mvc="sap.ui.core.mvc">
    <Input value="{path: '/company/revenue', formatter: '.roundToMillion'}"/>
</mvc:View>

If you use JavaScript, you can add a formatter function to the binding info with the formatter key. The formatter has a single parameter value, which is the value that is to be formatted. In the sample below, it is executed as a member of the control, meaning it can access additional control properties or model data.

Note:

The this context may not be the control. For more information, see this Context for Formatter Functions in Formatters.

oTextField.bindProperty("value", {
    path: "/company/title",
    formatter: (sValue) => sValue?.toUpperCase()
});

Because it can contain any JavaScript, the formatter function can be used for formatting a value and also for performing type conversions or calculating results, for example, to show a special traffic light image depending on a Boolean value:

oImage.bindProperty("src", {
    path: "/company/trusted",
    formatter: (bValue) => bValue ? "green.png" : "red.png"
}); 

Caution:

The framework only updates a binding when one of the properties included in the binding changes. If the formatter uses another property value that is not part of the binding definition, the framework won't know that the result depends on that additional property and could miss necessary updates. Therefore, make sure that you declare a composite binding referencing all necessary properties (maybe even from different models).

Using Data Types

The data type system enables you to format and parse data, as well as to validate whether the entered data lies within any defined constraints. OpenUI5 comes with several predefined and ready-to-use types, referred to as simple types. For more information, see Formatting, Parsing, and Validating Data.

Here's how you can use these types in an XML view:

<mvc:View
    controllerName="sap.ui.sample.App"
    xmlns="sap.m"
    xmlns:core="sap.ui.core"
    xmlns:mvc="sap.ui.core.mvc"
    core:require="{Integer: 'sap/ui/model/type/Integer'}">
    <Input value="{path: '/company/revenue', type: 'Integer'}"/>
</mvc:View>

You can also provide parameter values for some of the simple types in your XML view. These are declared as formatOptions, as you can see in the Float type sample below. Permitted formatOptions are properties of the corresponding data type. For more information, see the API Reference in the Demo Kit.

<mvc:View
    controllerName="sap.ui.sample.App"
    xmlns="sap.m"
    xmlns:mvc="sap.ui.core.mvc"
    core:require="{Float: 'sap/ui/model/type/Float'}">
    <Input
        value="{ 
            path: '/company/revenue', 
            type: 'Float',
            formatOptions: {
                minFractionDigits: 2,
                maxFractionDigits: 2
            }
    }"/>
</mvc:View>

Using JavaScript, you can define a type to be used for a property binding by adding it to the binding information by using the type key. The type can be set using either the class object of the type or an instance of the type. When using the class object, you can also provide formatOptions and constraints directly in the binding information.

Example: Using the Type Class

// "StringType" required from module "sap/ui/model/type/String"
// "Input" required from module "sap/m/Input"
// "Float" required from module "sap/ui/model/type/Float"

oTextField.bindProperty("value", "/company/name", StringType);

oControl = new Input({
    value: {
        path: "/company/revenue",
        type: Float,
        formatOptions: {
            minFractionDigits: 2,
            maxFractionDigits: 2
        }
    }
});

Example: Using a Type Instance

// "StringType" required from module "sap/ui/model/type/String"
// "Input" required from module "sap/m/Input"
// "Float" required from module "sap/ui/model/type/Float"

oTextField.bindProperty("value", "/company/name", new StringType());

oControl = new Input({
    value: {
        path: "/company/revenue",
        type: new Float({
            minFractionDigits: 2,
            maxFractionDigits: 2
        })
    }
});

Predefined data types also offer visual feedback for erroneous user input. To turn this feature on, add the following line to your controller's init function:

// "Messaging" required from module "sap/ui/core/Messaging"
Messaging.registerObject(this.getView(), true);

For other ways to activate this feature, such as using the handleValidation property, see Validation Messages.

You can define custom types by inheriting from sap.ui.model.SimpleType and implementing the three methods formatValue, parseValue, and validateValue. formatValue is called whenever the value in the model is changed to convert it to the type of the control property it is bound to, and may throw a FormatException. parseValue is called whenever the user has modified a value in the UI and the change is transported back into the model. It may throw a ParseException if the value cannot be converted. If parsing is successful, validateValue is called to check additional constraints, such as minimum or maximum value, and throws a ValidateException if any constraints are violated.

// "SimpleType" required from module "sap/ui/model/SimpleType"
// "ValidateException" required from module "sap/ui/model/ValidateException"

const Zipcode = SimpleType.extend("sap.ui.sample.Zipcode", {
    formatValue(oValue) {
        return oValue;
    },
    parseValue(oValue) {
        return oValue;
    },
    validateValue: function(oValue) {
        if (!/^(\d{5})?$/.test(oValue)) {
            throw new ValidateException("Zip code must have 5 digits!");
        }
    }
});

You can use your custom types in XML views or JavaScript in the same way as you would apply predefined types:

<mvc:View
    controllerName="sap.ui.sample.App"
    xmlns="sap.m"
    xmlns:core="sap.ui.core"
    xmlns:mvc="sap.ui.core.mvc"
    core:require="{Zipcode: 'sap/ui/sample/Zipcode'}">
    <Input value="{path: '/company/zip', type: 'Zipcode'}"/>
</mvc:View>

By default, all bindings of a model instance have the default binding mode of the model, but you can change this behavior if needed. When creating a PropertyBinding, you can specify a different binding mode, which is then used exclusively for this specific binding. Of course, a binding can only have a binding mode that is supported by the model in question.

// "JSONModel" required from module "sap/ui/model/json/JSONModel"
// "Input" required from module "sap/m/Input"
// "BindingMode" required from module "sap/ui/model/BindingMode"
const oModel = new JSONModel();
// default binding mode is two-way
oModel.setData(myData);
const oInputFirstName = new Input();
oInputFirstName.setModel(oModel);

// bind value property one way only
// propertyname, formatter function, binding mode
oInputFirstName.bindValue("/firstName", null, BindingMode.OneWay);
oInputFirstName.placeAt("target1");

const oInputLastName = new Input();
oInputLastName.setModel(oModel);
// bind value property two way (default)
oInputLastName.bindValue("/lastName");
oInputLastName.placeAt("target2");

In the example above, two Input fields are created and their value property is bound to the same property in the model. The first Input binding has a one-way binding mode, whereas the second Input has the default binding mode of the model instance, which is two-way. For this reason, when text is entered in the first Input, the value will not be changed in the model. This only happens if text is entered in the second Input. Then, of course, the value of the first Input will be updated as it has a one-way binding, that is, from model to view.

Related Information

Data Binding Tutorial Step 3: Create Property Binding

API Reference: sap.ui.base.ManagedObject.bindProperty

Binding Syntax

Formatting, Parsing, and Validating Data