Search code examples
data-bindingsapui5

Updating model in UI5, two-way data binding becomes one-way when using formatter


In my UI5-app, I have a table where each row contains a sap.m.Switch, which is bound to the model via formatter, since the data is coming from the DB as 1/0, rather than true/false, and that, probably, breaks the default two-way data binding.

To update a data model upon the editing value of this switch, I implemented the following change-event:

onChangeSwitch: function onChangeSwitch(oEvent) {
    let context = oEvent.oSource.getBindingContext();
    let itemIndex = context.sPath.substr(1);
    let oModel = this.getView().byId("idTablePersons").getModel();
    oModel.oData[itemIndex].isPersonActive = (oEvent.mParameters.state) ? 1 : 0;
    oModel.refresh();
}

It does work, but I'm not sure if it is a proper way to implement such logic. Is there a standard way to update a model after changing sap.m.Switch value?


Solution

  • I think you're approaching this the wrong way around. sap.m.Switch already has an attribute to indicate state which you can directly bind to a model.

    <Switch state="{IsPersonActive}" />
    

    Assuming you bound the items in the table to an unnamed model, that'll set the IsPersonActive flag on the bound line to true or false depending on the state of the switch.

    This also means it'll come out with the switches in the correct state if certain IsPersonActive flags are already set to true or false in your entity sets.


    (…) the data is coming from the DB as 1/0, rather than true/false (…).
    Is there a standard way to update a model after changing sap.m.Switch value?

    The two-way data binding fix from https://embed.plnkr.co/wwQXf8bTuiTP4RlP:

    NumericBoolean.js (minimal example):

    sap.ui.define([
      "sap/ui/model/SimpleType",
    ], Type => Type.extend('demo.model.type.NumericBoolean', {
      constructor: function() {
        Type.apply(this, arguments);
      },
      formatValue: iValue => !!+iValue,
      parseValue: bValue => bValue ? 1 : 0,
      validateValue: vValue => { /*validate...*/ },
    }));
    
    <Switch xmlns="sap.m" xmlns:core="sap.ui.core"
      core:require="{ NumericBoolean: 'demo/model/type/NumericBoolean' }"
      state="{
        path: '/1or0',
        type: 'NumericBoolean'
      }"
    />
    

    Important note:
    It's mandatory to keep the validateValue declaration even if the implementation is not provided, otherwise sap.m.Switch will not work correctly.