SAPUI5 (38) - OData Model 的单向绑定和双向绑定

单向绑定和双向绑定概述

所谓的单向绑定 (one-way binding),是指 OData model 与 UI 控件之间在数据绑定时, OData model 中数据的变化会同步反应在 UI 控件中,但 UI 控件数据的变化需要手工提交到 OData model;而双向绑定 (two-way binding),则是指 OData model 和 UI 控件的数据双向同步变化。

OData (v2) model 默认的是 one-way binding。OData model 刚开始只支持单向绑定,后来也支持 two-way binding。

使用 one-way 或者 two-way binding,可以进一步简化客户端代码的编写,同时对 CRUD 过程的控制更加精细。但推荐使用 one-way binding。

单向绑定

我们对上一篇程序代码进行修改,先来看看单向绑定。和上一篇比较,代码的变化集中在 App.controller.js 。首先贴出全部代码:

App.controller.js:

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

	var oModel;
	var sCurrentPath;
	var sCurrentEmp; // cureent employee
	var oEmployeeDialog;

	return Controller.extend("zui5_odata_sap_backend_crud.controller.App", {

		onInit: function() {
			oModel = this.getOwnerComponent().getModel();
			oModel.setUseBatch(false);
			this.getView().setModel(oModel);

			oEmployeeDialog = this.buildEmpDialog();
		},

		// Build employee dialog
		// If not exists, create an instance, otherwise, just get it.
		buildEmpDialog: function() {
			var oView = this.getView();

			var oEmpDialog = oView.byId("employeeDialog");
			if (!oEmpDialog) {
				oEmpDialog = sap.ui.xmlfragment(oView.getId(),
					"zui5_odata_sap_backend_crud.view.EmployeeDialog");
				
				oView.addDependent(oEmpDialog);

				// Attach press event for CancelButton
				var oCancelButton = oView.byId("CancelButton");
				oCancelButton.attachPress(function() {
					oEmpDialog.close();
				});
			}

			return oEmpDialog;
		},


		// onCreate event
		onCreate: function() {
			var oView = this.getView();
			oEmployeeDialog.open();
			oEmployeeDialog.setTitle("Create Employee");
			oView.byId("EmpId").setEditable(true);
			oView.byId("SaveEdit").setVisible(false);
			oView.byId("SaveCreate").setVisible(true);

			// clear
			oView.byId("EmpId").setValue("");
			oView.byId("EmpName").setValue("");
			oView.byId("EmpAddr").setValue("");

			// commit save operation
			oView.byId("SaveCreate").attachPress(function() {

				oModel.createEntry("/EmployeeCollection", {
					properties: {
						"Mandt": "100",
						"EmpId": oView.byId("EmpId").getValue(),
						"EmpName": oView.byId("EmpName").getValue(),
						"EmpAddr": oView.byId("EmpAddr").getValue()
					}
				});

				oModel.submitChanges();
				sap.m.MessageToast.show("Created Successfully.");

				// close dialog
				if (oEmployeeDialog) {
					oEmployeeDialog.close();
				}
			});
		},

		onEdit: function() {
			// no employee was selected
			if (!sCurrentEmp) {
				sap.m.MessageToast.show("No Employee was selected.");
				return;
			}

			var oView = this.getView();
			oEmployeeDialog.open();

			oEmployeeDialog.setTitle("Edit Employee");
			oView.byId("EmpId").setEditable(false);
			oView.byId("SaveEdit").setVisible(true);
			oView.byId("SaveCreate").setVisible(false);

			// Attach save event
			oView.byId("SaveEdit").attachPress(function() {

				// changes
				var oChanges = {
					"EmpName": oView.byId("EmpName").getValue(),
					"EmpAddr": oView.byId("EmpAddr").getValue()
				};

				oModel.setProperty(sCurrentPath + "/EmpName", oChanges.EmpName);
				oModel.setProperty(sCurrentPath + "/EmpAddr", oChanges.EmpAddr);

				if (oModel.hasPendingChanges()) {
					oModel.submitChanges();
					sap.m.MessageToast.show("Changes were saved successfully.");
				}
				
				// close dialog
				if (oEmployeeDialog) {
					oEmployeeDialog.close();
				}
			});
		},

		// onDelete event
		onDelete: function() {
			var that = this;

			// no employee was selected
			if (!sCurrentEmp) {
				sap.m.MessageToast.show("No Employee was selected.");
				return;
			}

			var oDeleteDialog = new sap.m.Dialog();
			oDeleteDialog.setTitle("Deletion");

			var oText = new sap.m.Label({
				text: "Are you sure to delete employee [" + sCurrentEmp + "]?"
			});
			oDeleteDialog.addContent(oText);

			oDeleteDialog.addButton(
				new sap.m.Button({
					text: "Confirm",
					press: function() {
						that.deleteEmployee();
						oDeleteDialog.close();
					}
				})
			);

			oDeleteDialog.open();
		},

		// deletion operation
		deleteEmployee: function() {
			oModel.remove(sCurrentPath, {
				success: function() {
					sap.m.MessageToast.show("Deletion successful.");
				},
				error: function(oError) {
					window.console.log("Error", oError);
				}
			});
		},

		onItemPress: function(evt) {
			var oContext = evt.getSource().getBindingContext();
			sCurrentPath = oContext.getPath();
			sCurrentEmp = oContext.getProperty("EmpName");

			oEmployeeDialog.bindElement(sCurrentPath);
		}
	});
});

说明一下主要代码的变化:

修改数据

单向绑定时,提交编辑的修改通过 setProperty() 方法将变更提交到 OData model,然后用 submitChanges() 方法将变更提交到数据源。如果想取消修改,则使用 resetChanges() 方法:

var oChanges = {
    "EmpName": oView.byId("EmpName").getValue(),
    "EmpAddr": oView.byId("EmpAddr").getValue()
};

oModel.setProperty(sCurrentPath + "/EmpName", oChanges.EmpName);
oModel.setProperty(sCurrentPath + "/EmpAddr", oChanges.EmpAddr);

if (oModel.hasPendingChanges()) {
    oModel.submitChanges();
    sap.m.MessageToast.show("Changes were saved successfully.");
}

oModel.hasPendingChanges() 确保有变更才将变更提交到数据源。

新增数据

新增数据,使用 ODataModel 的 createEntry() 方法,将新增的数据提交到 OData model,然后使用 submitChanges() 方法将请求队列中提交到数据源。如果想取消新增,使用 deleteCreatedEntry() 方法。

oModel.createEntry("/EmployeeCollection", {
    properties: {
        "Mandt": "100",
        "EmpId": oView.byId("EmpId").getValue(),
        "EmpName": oView.byId("EmpName").getValue(),
        "EmpAddr": oView.byId("EmpAddr").getValue()
    }
});

oModel.submitChanges();

双向绑定

双向绑定,也涉及到 Edit 及 Create 时候,UI 和 Model 的数据交互。但 UI 和 Model 之间变化自动同步。

1). 在 manifest.json 文件中设置默认的绑定模式:

"sap.ui5": {
    ...
		"models": {
			"i18n": {
				"type": "sap.ui.model.resource.ResourceModel",
				"settings": {
					"bundleName": "zui5_odata_sap_backend_crud.i18n.i18n"
				}
			},
			"": {
				"dataSource": "mainService",
				"type": "sap.ui.model.odata.v2.ODataModel",
				"settings": {
					"defaultBindingMode": "TwoWay",
					"metadataUrlParams": {
						"sap-documentation": "heading"
					}
				}
			}
		},
		...
	}

defaultBindingMode 设置为 TwoWay

2). Edit 不需要使用 setProperty() 方法:

oView.byId("SaveEdit").attachPress(function() {

    if (oModel.hasPendingChanges()) {
        oModel.submitChanges();
        sap.m.MessageToast.show("Changes were saved successfully.");
    }
    
    // close dialog
    if (oEmployeeDialog) {
        oEmployeeDialog.close();
    }
});

因为是双向绑定的,UI 中如果有数据变化 oModel.hasPendingChanges() 可以自动获得获取,不需要 setProperty()

3). Create 的代码:

oEmployeeDialog.unbindElement();
var oContext = oModel.createEntry("/EmployeeCollection", {
    properties: {
        "Mandt": "100"
    }
});
oEmployeeDialog.setBindingContext(oContext);

// commit save operation
oView.byId("SaveCreate").attachPress(function() {
    if (oView.byId("EmpId").getValue()) {
        oModel.submitChanges();
        sap.m.MessageToast.show("Created Successfully.");

        // close dialog
        if (oEmployeeDialog) {
            oEmployeeDialog.close();
        }
    } else {
        sap.m.MessageToast.show("Employee Id cannot be blank.");
    }
});

进入 Dialog 的时候,首先解除与已有数据的绑定,然后使用 createEntry() 方法创建一个新的 context。因为 Mandt 字段在 UI 固定为 100,UI 不用管,所以放在 properties 中。设定 oEmpoyeeDialogbindingContext 后,UI 的修改就自动提交给 Model 了。

源代码

参考资料

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值