Skip to Content

SAPUI5 Promises do not work (for me)

Hello experts,

New at the sport, probably I'm missing something basic here, scenario goes like this:

Within the app controller of my application (App.controller.js, onInit function) I'm performing a series of read operations on a named model, in order to have additional data ready, mainly for use by formatters in subsequent views. What I have done is using promises to make sure that data will be ready.

Problem is that application occasionally crashes when the root view (declared in manifest.json) is loaded after the app view because the formatter function can't find the data expected. Added a few break-points and observed the debugger:

a) stopping at the first read function

b) stopping at the promises condition at the end

c) stopping (and throwing error) at the formatter function at the subsequent view

d) stopping in the success function of oData read (resolve)

e) page freezes afterwards as result of the exception thrown above

"Normal" flow, when application doesn't crash goes like this:

a) stopping at the first read function

b) stopping at the promises condition at the end

c) stopping in the success function of oData read (resolve)

d) stopping at the readyToGo function (it's there just for temporary debugging)

e) stopping at the formatter function at the subsequent view

f) page display, everything in order

Judging by the above, I have reached the conclusion that my promises do not work, any ideas?

Code attached below, it's quite simple.

Best regards

Greg

sap.ui.define([
		"kristal/apps/agreements/controller/BaseController",
		"sap/ui/model/json/JSONModel"
	], function (BaseController, JSONModel) {
		"use strict";
                /* PROMISE VARIABLES */
		var oModelTypeDataDeferred = jQuery.Deferred();
		var oModelStatusDataDeferred = jQuery.Deferred();
		var oModelRoleDataDeferred = jQuery.Deferred();
		var oModelRefDataDeferred = jQuery.Deferred();
		var oModelExtOrgDataDeferred = jQuery.Deferred();
		var oModelInvolvementDataDeferred = jQuery.Deferred();
		
		return BaseController.extend("kristal.apps.agreements.controller.App", {
			onInit : function () {
                             /* CALLED AFTER PROMISES HAVE BEEN FULFILLED */
				var readyToGo = function() { 
					jQuery.sap.log.error("Ready!");
				};
	
				var oViewModel,
				fnSetAppNotBusy,
				iOriginalBusyDelay = this.getView().getBusyIndicatorDelay();
				oViewModel = new JSONModel({
					busy : true,
					delay : 0
				});
				this.setModel(oViewModel, "appView");


				fnSetAppNotBusy = function() {
					oViewModel.setProperty("/busy", false);
					oViewModel.setProperty("/delay", iOriginalBusyDelay);
				};


				this.getOwnerComponent().getModel().metadataLoaded().
					then(fnSetAppNotBusy);


					// apply content density mode to root view
				this.getView().addStyleClass(this.getOwnerComponent().getContentDensityClass());
			
				var oModel = this.getOwnerComponent().getModel("f4");
                         /* oData READ OPS */	
				oModel.metadataLoaded().then(function(){				
					// Initialize additional data 
					var sPath = "/Agreement_TypesSet";
					oModel.read(sPath, {
						success: function(oData, oResponse) {
							oModelTypeDataDeferred.resolve();
						},
						error: function(oError) {
							jQuery.sap.log.error("Error", oError);
						}
					});	
					sPath = "/Agreement_StatusesSet";
					oModel.read(sPath, {
						success: function(oData, oResponse) {
							oModelStatusDataDeferred.resolve();
						},
						error: function(oError) {
							jQuery.sap.log.error("Error", oError);
						}
					});
					sPath = "/Role_TypesSet";
					oModel.read(sPath, {
						success: function(oData, oResponse) {
							oModelRoleDataDeferred.resolve();
						},
						error: function(oError) {
							jQuery.sap.log.error("Error", oError);
						}
					});		
					sPath = "/Reference_TypesSet";
					oModel.read(sPath, {
						success: function(oData, oResponse) {
							oModelRefDataDeferred.resolve();
						},
						error: function(oError) {
							jQuery.sap.log.error("Error", oError);
						}
					});
					sPath = "/External_OrganizationsSet";
					oModel.read(sPath, {
						success: function(oData, oResponse) {
							oModelRefDataDeferred.resolve();
						},
						error: function(oError) {
							jQuery.sap.log.error("Error", oError);
						}
					});	
					sPath = "/Involvement_TypesSet";
					oModel.read(sPath, {
						success: function(oData, oResponse) {
							oModelInvolvementDataDeferred.resolve();
						},
						error: function(oError) {
							jQuery.sap.log.error("Error", oError);
						}
				        });
                           /* IF ALL PROMISES FULFILLED, PROCEED */	
				        jQuery.when(oModelTypeDataDeferred, oModelStatusDataDeferred, oModelRoleDataDeferred, oModelRefDataDeferred, + 
				        oModelExtOrgDataDeferred, oModelInvolvementDataDeferred).done().then( jQuery.proxy(readyToGo,this) );	
			}, ...remaining controller methods
Add comment
10|10000 characters needed characters exceeded

  • Get RSS Feed

2 Answers

  • Best Answer
    May 10 at 09:45 AM

    Solution found in the form of declaring and initializing the model inside Component.js and putting router initialization inside the promise condition, thanks to Jorg from SO :-)

    Add comment
    10|10000 characters needed characters exceeded

  • May 09 at 05:08 PM

    I think it's less that your promises don't work and more that there is nothing making the view wait to render until your promises are resolved. The rest of the UI5 processing doesn't know about any promises you create in your controller context. It sounds like your formatter is trying to access something that doesn't yet exist. The usual way to deal with that would be to put guards in your formatter like this:

    if(foo) {
       ...
    }

    Your formatter will be called whenever the bound value is updated, so once the value changes your formatter will be called again, the values it is looking for will exist, and all will be well.

    It might be better to share a little bit more about what you're trying to accomplish here, as it seems like you're doing a lot of stuff manually (all those model reads) that should be happening automatically if you are binding to delivered controls.

    Add comment
    10|10000 characters needed characters exceeded

    • I think you should ask a new question laying out this scenario including what you've already done (without the promises part). There are all kinds of ways to make this work including associations. But in an sap.m.Select control you can bind the items displayed in the control to a different entity set than the control itself is bound to, which is probably what you want to do.