Skip to Content

oData Model declared in component.js - where are my data?

Hello experts,

I have an application which is working fine but has a slight problem, oData in certain cases are not ready when the first view is loaded. The app uses 2 data models, both of them declared in manifest.json, one anonymous for the main work and another one named "f4" for handling of some entities used in certain formatters and dropdowns. Data for the latter model are getting loaded via a series of read operations in the init function of the root view. Leaving aside the issue mentioned in the beginning, everything else works.

Thanks to some expert advice here, found the cause of my problem. Router gets initialized before loading of data, so I decided to move the read ops from the root view to component.js. As soon as I did this, I experienced the problem of being unable to access the model declared in manifest.json, so I removed the definition of the named model from there, declared the model inside component.js onInit function and made the application aware of it by using the sap.ui.getCore().setModel(oModel, "f4") statement.

Here comes the problem. Model is known to the app but seems to be empty from data. I know that data are getting loaded because I debugged the application and observed the app passing from all the read success functions before successfully initializing the router. Read in another post that doing this in onInit isn't the best possible practice, so I moved again functionality from the onInit to onAfterRendering function as advised but results are still the same, no data.

So the question is: How can I access an oData model, get the required entries and made them known to the app BEFORE router initialization?

Component.js attached below, thanks for the time to read this.

sap.ui.define([
		"sap/ui/core/UIComponent",
		"sap/ui/Device",
		"kristal/apps/agreements/model/models",
		"kristal/apps/agreements/controller/ErrorHandler"
	], function (UIComponent, Device, models, ErrorHandler) {
		"use strict";
		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 UIComponent.extend("kristal.apps.agreements.Component", {


			metadata : {
				manifest: "json"
			},


			/**
			 * The component is initialized by UI5 automatically during the startup of the app and calls the init method once.
			 * In this function, the FLP and device models are set and the router is initialized.
			 * @public
			 * @override
			 */
			init : function () {
				
				// call the base component's init function
				UIComponent.prototype.init.apply(this, arguments);


				// initialize the error handler with the component
				this._oErrorHandler = new ErrorHandler(this);


				// set the device model
				this.setModel(models.createDeviceModel(), "device");
				// set the FLP model
				this.setModel(models.createFLPModel(), "FLP");
				//this.getRouter().initialize();	
			},
			onAfterRendering: function () {

				var readyToGo = function() { 
					this.getRouter().initialize();	
					jQuery.sap.log.error("Ready!");
				};				

  			        var sUrl = "/DEV/sap/opu/odata/SAP/ZCONTRACTS_SRV/";
		                var oModel = new sap.ui.model.odata.ODataModel(sUrl, true);
		                sap.ui.getCore().setModel(oModel, "f4");


				//var oModel = this.getOwnerComponent().getModel("f4");	
				// Initialize additional data - UITGKA
				var sPath = "/Agreement_TypesSet";
				oModel.read(sPath, {
					success: function(oData, oResponse) {
						//sap.ui.getCore().getModel("f4").setProperty("/Agreement_TypesSet", oData);
						oModelTypeDataDeferred.resolve();
					},
					error: function(oError) {
						jQuery.sap.log.error("Error", oError);
					}
				});	
				sPath = "/Agreement_StatusesSet";
				oModel.read(sPath, {
					success: function(oData, oResponse) {
						//sap.ui.getCore().getModel("f4").setProperty("/Agreement_StatusesSet", oData);
						oModelStatusDataDeferred.resolve();
					},
					error: function(oError) {
						jQuery.sap.log.error("Error", oError);
					}
				});
				sPath = "/Role_TypesSet";
				oModel.read(sPath, {
					success: function(oData, oResponse) {
						//sap.ui.getCore().getModel("f4").setProperty("/Role_TypesSet", oData);
						oModelRoleDataDeferred.resolve();
					},
					error: function(oError) {
						jQuery.sap.log.error("Error", oError);
					}
				});		
				sPath = "/Reference_TypesSet";
				oModel.read(sPath, {
					success: function(oData, oResponse) {
						//sap.ui.getCore().getModel("f4").setProperty("/Reference_TypesSet", oData);
						oModelRefDataDeferred.resolve();
					},
					error: function(oError) {
						jQuery.sap.log.error("Error", oError);
					}
				});
				sPath = "/External_OrganizationsSet";
				oModel.read(sPath, {
					success: function(oData, oResponse) {
						//sap.ui.getCore().getModel("f4").setProperty("/External_OrganizationsSet", oData);
						oModelRefDataDeferred.resolve();
					},
					error: function(oError) {
						jQuery.sap.log.error("Error", oError);
					}
				});	
				sPath = "/Involvement_TypesSet";
				oModel.read(sPath, {
					success: function(oData, oResponse) {
						//sap.ui.getCore().getModel("f4").setProperty("/Involvement_TypesSet", oData);
						oModelInvolvementDataDeferred.resolve();
					},
					error: function(oError) {
						jQuery.sap.log.error("Error", oError);
					}
				});					
				jQuery.when(oModelTypeDataDeferred, oModelStatusDataDeferred, oModelRoleDataDeferred, oModelRefDataDeferred, + 
				 oModelExtOrgDataDeferred, oModelInvolvementDataDeferred).done().then( jQuery.proxy(readyToGo,this) );				
			},
			/**
			 * The component is destroyed by UI5 automatically.
			 * In this method, the ErrorHandler is destroyed.
			 * @public
			 * @override
			 */
			destroy : function () {
				this._oErrorHandler.destroy();
				// call the base component's destroy function
				UIComponent.prototype.destroy.apply(this, arguments);
			},


			/**
			 * This method can be called to determine whether the sapUiSizeCompact or sapUiSizeCozy
			 * design mode class should be set, which influences the size appearance of some controls.
			 * @public
			 * @return {string} css class, either 'sapUiSizeCompact' or 'sapUiSizeCozy' - or an empty string if no css class should be set
			 */
			getContentDensityClass : function() {
				if (this._sContentDensityClass === undefined) {
					// check whether FLP has already set the content density class; do nothing in this case
					if (jQuery(document.body).hasClass("sapUiSizeCozy") || jQuery(document.body).hasClass("sapUiSizeCompact")) {
						this._sContentDensityClass = "";
					} else if (!Device.support.touch) { // apply "compact" mode if touch is not supported
						this._sContentDensityClass = "sapUiSizeCompact";
					} else {
						// "cozy" in case of touch support; default for most sap.m controls, but needed for desktop-first controls like sap.ui.table.Table
						this._sContentDensityClass = "sapUiSizeCozy";
					}
				}
				return this._sContentDensityClass;
			}


		});


	}
);

Add comment
10|10000 characters needed characters exceeded

  • Get RSS Feed

3 Answers

  • Best Answer
    May 14 at 06:15 PM

    Model declaration is wrong here. Model IS visible within component.js, the only thing needed was just a this.getModel("f4");

    Thanks to @BoghyonHoffmann at SO

    Add comment
    10|10000 characters needed characters exceeded

  • May 11 at 10:55 AM

    You could set the model before you initialize the view controllers.

    The following statement:

    // call the base component's init function
    UIComponent.prototype.init.apply(this, arguments);

    would be place at the end of the init function in the Component.js

    Add comment
    10|10000 characters needed characters exceeded

    • Hello,

      This statement already exists at the beginning of the init function.

      a) Do you mean just transferring it from the beginning to the end?

      b) How I will access the model within the onAfterRendering function that performs the read operations?

      Thanks, cheers
      Greg

  • May 11 at 04:16 PM

    why not call the models in the view init() method ?

    another option is to call the router initialize method after all the calls to model are completed. From the code above there are two places router is initialized, one in init() method and the other in 'onAfterRendering' which is called after all the models are called........

    Remove router initialize in 'init' method and try.

    Add comment
    10|10000 characters needed characters exceeded

    • Hi, if you look the last part of the post, this is exactly what I have done - model still visible but "empty". Been told somewhere else that I need to get back to the manifest.json logic, encapsulate component.js inside a component container and set the parameter propagateModel to true. The only problem is that I din't find any sample and the way I did it doesn't seem to work :-)