Skip to Content

App malfunctions after entering new entry mode

Hello experts,

I have an app based on the worklist view and I try to adapt new entry functionality. Application flow is simple up to a point, goes like this: user sees the worklist, clicks in one of the entries and he's transferred to a detail object view which holds a lot of information in different tabs. As long as I work with existing entries everything goes smooth. As soon as I press my "Add" button (which follows the same route but binds the detail view to a new entry) at the bottom of the worklist, app goes a little crazy. To begin with, when I press the save button, acts like nothing is happening and I need to press it a 2nd time. Of course, something is happening. Debugger passes twice from my save function and, for some reason when I debug the application code inside the save event and check for pending changes in the model, instead of seeing my new entry...I see my new entry and the last edited entry as well.

And there's more to it. If I try first thing in the app to enter a new entry, if backend validation passes, record is created. If validation doesn't pass and the record is not inserted, as soon as the request is completed (success, no oData error), the oData entry changes from a new entry (id-nnnnnnn....) to an entry with primary key zeroes, which the system tries to use with MERGE when I retry, resulting to oData error. I can understand why this happening, SAPUI5 considers the job done and changes the entry but I don't know how to handle it. In case of validation error, I create again a new entry and I rebind (or at least I think I do so, even though that they look alright in the UI5 inspector) the controls and but I'm left with two pending entries in the model.

I tried this logic with a different approach (inserting with the use of a dialog instead of using navigation and. regardless other small issues I faced, the oData part worked in the 2nd case which is applicable here, so this must mean that I'm doing something not really good with my view binding. Any help?

Controller code attached below, everything happens in there, it's big so I attach only the beginning part of interest.

Thanks in advance

Greg

sap.ui.define([
		"kristal/apps/agreements/controller/BaseController",
		"sap/ui/model/json/JSONModel",
		"sap/ui/core/routing/History",
		"sap/m/MessageToast",
		"sap/m/MessageBox",
		"kristal/apps/agreements/model/formatter",
		"sap/ui/commons/ValueHelpField",
		"sap/m/Dialog",
		"sap/ui/ux3/ToolPopup"
	], function (
		BaseController,
		JSONModel,
		History,
		MessageToast,
		MessageBox,
		formatter,
		ValueHelpField,
		Dialog,
		ToolPopup
	) {
		"use strict";
		// Agreement maintenance dialog
		var oActionDialog;
		// External Organizations tab vars
		var oPartnerControlToUpdate; 
		var oVendorControlToUpdate; 
		var oHelpTable = new sap.ui.table.Table({
		    selectionMode: sap.ui.table.SelectionMode.Single,
		    visibleRowCount: 7,
		    width: "300pt"
		});
	
		var sHeaderScope;
		return BaseController.extend("kristal.apps.agreements.controller.Object", {
			formatter: formatter,

			/**
			 * Called when the worklist controller is instantiated.
			 * @public
			 */
			onInit : function () {
				
				// Model used to manipulate control states. The chosen values make sure,
				// detail page is busy indication immediately so there is no break in
				// between the busy indication for loading the view's meta data
				var iOriginalBusyDelay,
					oViewModel = new JSONModel({
						busy : true,
						delay : 0
					});


				this.getRouter().getRoute("object").attachPatternMatched(this._onObjectMatched, this);


				// Store original busy indicator delay, so it can be restored later on
				iOriginalBusyDelay = this.getView().getBusyIndicatorDelay();
				this.setModel(oViewModel, "objectView");
				this.getOwnerComponent().getModel().metadataLoaded().then(function () {
						// Restore original busy indicator delay for the object view
						oViewModel.setProperty("/delay", iOriginalBusyDelay);
					}
				);
				// Header tab initialization actions take place on binding
				// depending on the scope (C: Create, U: Update)
				// External Organisations tab initialization
				this.getView().byId("saveExtOrgButton").setVisible(false);
				this.getView().byId("cancelExtOrgButton").setVisible(false);	
				this.getView().byId("addExtOrgButton").setVisible(false);	
				this.getView().byId("deleteExtOrgButton").setVisible(false);	
				this.oExtOrgTable = this.getView().byId("idExtOrgsTable");
				this._bindExtOrgReadOnly();
				this.rebindExtOrgTable(this.oExtOrgEditableTemplate, "Edit");					
				// References tab initialization
				this.getView().byId("saveRefButton").setVisible(false);
				this.getView().byId("cancelRefButton").setVisible(false);	
				this.getView().byId("addRefButton").setVisible(false);	
				this.getView().byId("deleteRefButton").setVisible(false);	
				this.oRefTable = this.getView().byId("idRefsTable");
				this._bindRefReadOnly();
				this.rebindRefTable(this.oRefEditableTemplate, "Edit");				
				// Roles tab initialization
				this.getView().byId("saveRoleButton").setVisible(false);
				this.getView().byId("cancelRoleButton").setVisible(false);	
				this.getView().byId("addRoleButton").setVisible(false);	
				this.getView().byId("deleteRoleButton").setVisible(false);	
				this.oRoleTable = this.getView().byId("idRolesTable");
				this._bindRoleReadOnly();
				this.rebindRoleTable(this.oRoleEditableTemplate, "Edit");					
			},
			onBeforeRendering: function () {


			},
			onAfterRendering: function () {
				
			},			

			/**
			 * Event handler when the share in JAM button has been clicked
			 * @public
			 */
			onShareInJamPress : function () {
				var oViewModel = this.getModel("objectView"),
					oShareDialog = sap.ui.getCore().createComponent({
						name: "sap.collaboration.components.fiori.sharing.dialog",
						settings: {
							object:{
								id: location.href,
								share: oViewModel.getProperty("/shareOnJamTitle")
							}
						}
					});
				oShareDialog.open();
			},


			/**
			 * Event handler  for navigating back.
			 * It there is a history entry or an previous app-to-app navigation we go one step back in the browser history
			 * If not, it will replace the current entry of the browser history with the worklist route.
			 * @public
			 */
			onNavBack : function() {
				var sPreviousHash = History.getInstance().getPreviousHash(),
					oCrossAppNavigator = sap.ushell.Container.getService("CrossApplicationNavigation");


				if (sPreviousHash !== undefined || !oCrossAppNavigator.isInitialNavigation()) {
					history.go(-1);
				} else {
					this.getRouter().navTo("worklist", {}, true);
				}
			},

			/**
			 * Binds the view to the object path.
			 * @function
			 * @param {sap.ui.base.Event} oEvent pattern match event in route 'object'
			 * @private
			 */
			_onObjectMatched : function (oEvent) {
				var sObjectId =  oEvent.getParameter("arguments").objectId;
				
				var oModel = this.getView().getModel();
				oModel.resetChanges();	
				oModel.updateBindings();
				oModel.refresh();
				if (sObjectId === "0") {
					sHeaderScope = "C";
					var oEntry = oModel.createEntry("/AgreementsSet");
					this.getModel().metadataLoaded().then( function() {
						var sObjectPath = oEntry.sPath;
						//this.getView().setBindingContext(oEntry);
						this._bindView(sObjectPath);
					}.bind(this));
					this.getView().byId("saveHeaderButton").setVisible(true);
					this.getView().byId("cancelHeaderButton").setVisible(true);
					this.getView().byId("editHeaderButton").setVisible(false);					
					this._bindHeaderEdit();
				} else {
					sHeaderScope = "U";					
					this.getModel().metadataLoaded().then( function() {
						var sObjectPath = this.getModel().createKey("AgreementsSet", {
							AgrId :  sObjectId
						});
						this._bindView("/" + sObjectPath);
					}.bind(this));
					this.getView().byId("saveHeaderButton").setVisible(false);
					this.getView().byId("cancelHeaderButton").setVisible(false);
					this.getView().byId("editHeaderButton").setVisible(true);								
					this._bindHeaderReadOnly();
				}
			},

			/**
			 * Binds the view to the object path.
			 * @function
			 * @param {string} sObjectPath path to the object to be bound
			 * @private
			 */
			_bindView : function (sObjectPath) {
				var oViewModel = this.getModel("objectView"),
					oDataModel = this.getModel();


				this.getView().bindElement({
					path: sObjectPath,
					events: {
						change: this._onBindingChange.bind(this),
						dataRequested: function () {
							oDataModel.metadataLoaded().then(function () {
								// Busy indicator on view should only be set if metadata is loaded,
								// otherwise there may be two busy indications next to each other on the
								// screen. This happens because route matched handler already calls '_bindView'
								// while metadata is loaded.
								oViewModel.setProperty("/busy", true);
							});
						},
						dataReceived: function () {
							oViewModel.setProperty("/busy", false);
						}
					}
				});
			},


			_onBindingChange : function () {
				var oView = this.getView(),
					oViewModel = this.getModel("objectView"),
					oElementBinding = oView.getElementBinding();


				// No data for the binding
				if (!oElementBinding.getBoundContext()) {
					this.getRouter().getTargets().display("objectNotFound");
					return;
				}


				var oResourceBundle = this.getResourceBundle(),
					oObject = oView.getBindingContext().getObject(),
					sObjectId = oObject.AgrId,
					sObjectName = oObject.AgrId;


				// Everything went fine.
				oViewModel.setProperty("/busy", false);
				oViewModel.setProperty("/saveAsTileTitle", oResourceBundle.getText("saveAsTileTitle", [sObjectName]));
				oViewModel.setProperty("/shareOnJamTitle", sObjectName);
				oViewModel.setProperty("/shareSendEmailSubject",
				oResourceBundle.getText("shareSendEmailObjectSubject", [sObjectId]));
				oViewModel.setProperty("/shareSendEmailMessage",
				oResourceBundle.getText("shareSendEmailObjectMessage", [sObjectName, sObjectId, location.href]));
			},
			// Header tab functions	
			onHeaderSave: function(ev) {


				var that;
				var oModelUpdateDeferred = jQuery.Deferred();
				var bCheckSuccess;
				var oModel;
				var oControl;
				
				that = this;
				oModel = this.getView().getModel();
				oControl = this.getView().byId("objectAgreementHeaderForm");
				this._checkMessagePopoverState();


				// abort if the  model has not been changed
				if (!oModel.hasPendingChanges()) {
					MessageBox.information(
						this.getResourceBundle().getText("noChangesMessage"), {
							id: "noChangesInfoMessageBox",
							styleClass: that.getOwnerComponent().getContentDensityClass()
						}
					);
					return;
				}
				
				oModel.attachEventOnce("batchRequestCompleted", function(oEvent) {
				// Get control to display message list next to 
				//var oControl = sap.ui.getCore().byId("application-agreements-display-component---object--objectAgreementHeaderForm");


					if (that._checkIfBatchRequestSucceeded(oEvent)) {
						that._renderSAPMessages(oEvent.getParameters().response.responseText,
						oEvent.getParameters().response.responseText.indexOf("sap-message: {"),
						oControl);
						if (oEvent.getParameters().response.responseText.indexOf("sap-message: {") < 0) {
							bCheckSuccess = true;
						} else {
							bCheckSuccess = false;	
						}	
 						oModelUpdateDeferred.resolve();	
					}
				});
					
				oModel.submitChanges({
					success: function(oData, sResponse) {
					},
					error: function(oError) {
						jQuery.sap.log.error("oData Failure", oError);
					}
				});	
				var readyToGo = function() {
					if (bCheckSuccess === true) {
						//if (sScope === "Edit") {
							this.getView().byId("saveHeaderButton").setVisible(false);
							this.getView().byId("cancelHeaderButton").setVisible(false);
							this.getView().byId("editHeaderButton").setVisible(true);							
							this._bindHeaderReadOnly();
						/*} else {
							this.getParent().getParent().close();	
						}*/
					} else {
						if (sHeaderScope === "C") {
							oModel.resetChanges();
							var oEntry = oModel.createEntry("/AgreementsSet");
							this.getModel().metadataLoaded().then( function() {
								var sObjectPath = oEntry.sPath;
								this._bindView(sObjectPath);
								this._bindHeaderEdit();
							}.bind(this));								
						}
					}
				};
				jQuery.when(oModelUpdateDeferred).done().then( jQuery.proxy(readyToGo, this) );				
			},				
			onHeaderEdit: function(oEvent) {
				
				if (oEvent.getSource() === this.getView().byId("editHeaderButton")) {
					this.getView().byId("editHeaderButton").setVisible(false);
					this.getView().byId("saveHeaderButton").setVisible(true);
					this.getView().byId("cancelHeaderButton").setVisible(true);					
				}
				/*	sScope = "Edit";
				} else {
					sScope = "Add";
				}*/
				this._bindHeaderEdit();	
			},	
			onHeaderCancel: function() {


				var that;				
				var oModel;
				


				//if (sScope === "Edit") {
					that = this;
					oModel = this.getView().getModel();
					this.getView().byId("cancelHeaderButton").setVisible(false);
					this.getView().byId("saveHeaderButton").setVisible(false);
					this.getView().byId("editHeaderButton").setVisible(true);
					this._bindHeaderReadOnly();
				/*} else {
					that = this.getParent().getParent().getParent().getController();
					oModel = this.getParent().getParent().getParent().getModel();
					this.getParent().getParent().close();
				}*/
				that._checkMessagePopoverState();					
				oModel.resetChanges();
			},
			_bindHeaderEdit: function() {


				var oHeaderItemTemplate = new sap.ui.core.ListItem({ key:"{f4>AgrTypeid}", text:"{f4>AgrTypeid}", additionalText:"{f4>AgrTypetxt}"});
				var oHeaderCurrencyTemplate = new sap.ui.core.ListItem({ key:"{f4>Curr}", text:"{f4>Curr}", additionalText:"{f4>Currencytxt}"});


				this.getView().byId("objectAgreementHeaderForm").removeAllContent();				
				var lAgrTypeid = new sap.m.Label({text: "{i18n>agreementHeaderAgrTypeid}"});
				var sAgrTypeid = new sap.m.ComboBox({
									selectedKey: "{AgrTypeid}",
									showSecondaryValues :  true,
									items: {
										path: "f4>/Agreement_TypesSet",
										template: oHeaderItemTemplate,										
										templateShareable: "false"},
										width: "15em"
						}).bindProperty("value", "AgrTypeid");		
				var lShorttitle = new sap.m.Label({text: "{i18n>agreementHeaderShortText}"});
				var sShorttitle = new sap.m.Input({value: "{Shorttitle}"});
				var lComment = new sap.m.Label({text: "{i18n>agreementHeaderComment}"});
				var sComment = new sap.m.Input({value: "{AgrComment}"});	
				var lCurrency = new sap.m.Label({text: "{i18n>agreementHeaderCurrency}"});
				//var sCurrency = new sap.m.Input({value: "{Curr}", width: "3em"});	
				var sCurrency = new sap.m.ComboBox({
									selectedKey: "{Curr}",
									showSecondaryValues :  true,
									items: {
										path: "f4>/Allowed_CurrenciesSet",
										template: oHeaderCurrencyTemplate,										
										templateShareable: "false"},
										width: "15em"
						}).bindProperty("value", "Curr");					
	
				var lPrice = new sap.m.Label({text: "{i18n>agreementHeaderPrice}"});
				var sPrice = new sap.m.Input({value: "{Price}",	width: "7em"});					
				this.getView().byId("objectAgreementHeaderForm").addContent(lAgrTypeid);
				this.getView().byId("objectAgreementHeaderForm").addContent(sAgrTypeid);				
				this.getView().byId("objectAgreementHeaderForm").addContent(lShorttitle);
				this.getView().byId("objectAgreementHeaderForm").addContent(sShorttitle);
				this.getView().byId("objectAgreementHeaderForm").addContent(lComment);
				this.getView().byId("objectAgreementHeaderForm").addContent(sComment);
				this.getView().byId("objectAgreementHeaderForm").addContent(lCurrency);
				this.getView().byId("objectAgreementHeaderForm").addContent(sCurrency);				
				this.getView().byId("objectAgreementHeaderForm").addContent(lPrice);
				this.getView().byId("objectAgreementHeaderForm").addContent(sPrice);				
			},...
Add comment
10|10000 characters needed characters exceeded

  • Get RSS Feed

0 Answers