Is it possible to bind sap.ui.base.ManagedObject to the view?

大兔子大兔子 提交于 2021-02-04 12:43:04

问题


I have a view that shows the employee name in the sap.m.Input control as below

<mvc:View
  controllerName="com.naveen.test.managedobject.controller.Employee"
  xmlns="sap.m"
  xmlns:mvc="sap.ui.core.mvc"
  height="100%"
>
  <Input
    value="{/name}"
    liveChange="onDataChange"
    type="Text"
  />
</mvc:View>

And the model class is as shown here based on this hint.

sap.ui.define([
  "sap/ui/base/ManagedObject"
], function(ManagedObject) {
  "use strict";

  return ManagedObject.extend("com.naveen.test.managedobject.model.Employee", {
    metadata: {
      properties: {
        name: {
          type: "string",
          defaultValue: ""
        }
      }
    },

    set name(iName) {
      this.setName(iName);
    },

    get name() {
      return this.getName();
    }

  });
});

And in the controller, I am just creating one object of Employee model and setting it on the view as below.

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

  return Controller.extend("com.naveen.test.managedobject.controller.Employee", {
    onInit: function() {
      var employee = new Employee({
        name : "Naveen"
      });
      this.model = new JSONModel(employee);
      this.getView().setModel(this.model);
    },

    onDataChange: function(oEvent) {
      var value = oEvent.getParameter("value");
      console.log("Value in control", value);
      console.log("Value in model", this.model.getData().getName());
    }

  });
});

But the view is not taking the data from the model and changes in the model are not updated in the view. Is there any error in this method or how can we bind the managed object's property to the view?


回答1:


Since 1.58, there are no workarounds needed anymore thanks to the ManagedObjectModel (MOM).

sap.ui.model.base.ManagedObjectModel
The ManagedObjectModel class can be used for data binding of properties and aggregations for managed objects.

Its constructor accepts anything that is extended from the ManagedObject meaning it can be even used with the UIComponent.

sap.ui.define([
  "sap/ui/core/UIComponent",
  "sap/ui/model/base/ManagedObjectModel"
], function(UIComponent, MOM) {
  "use strict";

  return UIComponent.extend("my.Component", {
    metadata: {
      manifest: "json",
      properties: {
        "myProperty": {
          type: "string",
          defaultValue: "Hello MOM" 
        }
      }
    },

    init: function() {
      UIComponent.prototype.init.apply(this, arguments);
      this.setModel(new MOM(this), "component");
    },

    // ...

  });
});

Then in the view: <Input value="{component>/myProperty}"/> which outputs "Hello MOM" by default.

Internally, MOM is also used in XMLComposite controls and in the new event handling concept.


Here is a demo with the "Employee" example mentioned in the question. The following ManagedObjects were created for the purpose of the demo:

  • ManagedObject "Department" with aggregation "employees"
  • ManagedObject "Employee" with property "name"

Link: https://embed.plnkr.co/bWFidnHVabwaoqQV

As you can see, binding ManagedObjectModel works seamlessly.




回答2:


Yes that is possible, but with a little workaround. I have a custom BusinessObjectModel, which is an inheritance of the standard JSONModel, but every entry in the model is in reality an instance of a class.

See this github repository: https://github.com/FiddleBe/UI5-BusinessObjectModel It's an example of how to use object instances as model entries and bind object properties to the view.

There's a lot of additional functionality in there, like offline persistance, which you may not need.

My base BusinessObject (which you have to inherit for your employee) is based on an EventProvider, instead of the managedobject. but since the managedobject inherits the EventProvider, perhaps it's possible to change the extension of the bas BusinessObject... anyway..

A couple of important notes: You need to raise an event (in my implementation PropertyUpdated) whenever a property is "set" from your setter:

this.fireEvent("propertyUpdated", {
     reason: sap.ui.model.ChangeReason.Binding,
     path: "/<yourpropertyname>",
     value: this.<yourproperty>
});

In the model inheritance, you need to subscribe to this event, of every object instance present in the entries set. you can do this in a setData inheritance

ObjectModel.prototype.setData = function (oData, bMerge) {
   var aData = [];
   this.oData = [];

   if (oData instanceof Array) {
       aData = oData;
   } else {
       aData.push(oData);
   }

   for (var i = 0; i < aData.length; i++) {
       var oObject = aData[i];
       if (this.objectClass && oObject instanceof this.objectClass) {
         //is already an object instance.. don't change.
         oObject.attachPropertyUpdated({ basePath: "/" + i }, this.onPropertyUpdated, this);
       }else if (this.objectClass) {
          oObject = new this.objectClass.getObject(aData[i], "/" + i);
          oObject.attachPropertyUpdated({ basePath: "/" + i }, this.onPropertyUpdated, this);
        } else {
           oObject = aData[i];
        }
        this.oData = this.oData.concat(oObject);
    }

    arguments[0] = this.oData.concat();//not very clean

    Model.prototype.setData.apply(this, arguments);
};

have a look at the library in github as well: https://github.com/FiddleBe/library It contains a more up-to date implementation.




回答3:


I can't really test this so there might be issues with the below, but the idea is to:

  • instantiate a JSON model and attach it to the view that contains {name: 'Naveen'}.
  • instantiate a new Employee that points to the name in the JSON model
  • attach the employee to the screen

so something like:

this.getView().setModel(new JSONModel({name:'Naveen'}));

// this is UI5 databinding. `{/name}` references the variable called 'name'
// in the unnamed model, like above
var employee = new Employee({name: '{/name}'); 
this.getView().addContent(employee); 

You might want to consider reading through the walk-through of an application in the OpenUI5 documentation, which will tell you all about data binding. Here's a link to the latest version (1.48), you can find other versions as well.


The clarify the encapsulation, this is done by the JSON model. Data can be accessed using

this.getModel().getProperty('/name') //get
this.getModel().setProperty('/name', 'NotNaveen') //set. 

This will propagate the change in name through the binding system (in this case it'll change the name in Employee).

If you want an input field bound to name in the model:

this.getView().addContent(new Input({value: '{/name}'));

What you could do, is extend JSONModel and call it EmployeeModel. In the constructor, set up whatever structure you want and call the super constructor. It can be used in the same way a JSONModel can - binding etc - while also giving you some control over the data inside.

So to actually answer your question: No, you should not use ManagedObject this way, use the JSONModel.



来源:https://stackoverflow.com/questions/45591930/is-it-possible-to-bind-sap-ui-base-managedobject-to-the-view

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!