1
votes

I've got two models defined in my Component.js. One is a list of all contacts and the other is only the logged in contact. Now i want to check in my controller if the logged in contact is already existing in the list of all contacts. I compare the registrationToken from the list agains the token from the logged in contact. But when i loop through the list the length is 0 because of asynchronous communication. I saw the attachRequestCompleted function but now i got another problem... the onInit-function is already finished when my attach-function is fill my view-Model..

onInit : function(){
    var gLocalContact = sap.ui.getCore().getModel("gLocalContact");
    var gRemoteContacts = sap.ui.getCore().getModel("gRemoteContacts");

    gRemoteContacts.attachRequestCompleted( function() {
        ... if ... setProperty to gLocalContact.getProperty("/registrationToken")...
        console.log("I should be the first log to get the data in view");
    });

    console.log("I should be the second log!");
    this.getView().setModel(gLocalContact, "localContact");
}

The first log in the attach-function should be first because there i define some data to gLocalContact which i need in my view. Another problem is that i have no access to my gLocalContact variable....

1

1 Answers

2
votes

This is a little bit ugly because SAPUI5 does not support promises. So inside your view you don't know if the requestCompleted event will be fired or if the data has already been loaded. There are some solutions comming to my mind:

  1. Attach the requestCompleted eventhandler in your component before you call loadData(). Then you can be shure that you will get the event. You would have to build your view to handle an empty gLocalContact model though. But as soon as the model is populated with data the bindings will update the view.

  2. Put the remaining stuff of your onInit() into your eventhander. To be sure to get the event do a check if there is already data in your model, and if so call your eventhandler manually to have it run at least once.

  3. Use jQuerys Promises to synchronize. This allows you to wait for the second model too:

onInit : function(){
  var gLocalContact = sap.ui.getCore().getModel("gLocalContact");
  var gRemoteContacts = sap.ui.getCore().getModel("gRemoteContacts");

  console.log("Wait some seconds for the data...");
  var localContactPromise = this.getPromise(gLocalContact, "/origin");
  localContactPromise.done(function() {
    //same code as before but this time you can be shure its called.
    //... if ... setProperty to
    //gLocalContact.getProperty("/registrationToken")...
    console.log("I should be the first log to get the data in view");
  });

  var remoteContactsPromise = this.getPromise(gRemoteContacts,"/origin"); //Wait for the other model to
  $.when(localContactPromise, remoteContactsPromise).done(function(){ 
    //When both models are loaded do this
    console.log("I should be the second log!");
    this.getView().setModel(gLocalContact, "localContact");
    this.byId("label").setText("all loaded");
  }.bind(this));
},
getPromise:function(oModel, pathToTestForData){
  var deferred = $.Deferred();
  if (oModel.getProperty(pathToTestForData))
    deferred.resolve(); //Data already loaded
  else
    oModel.attachRequestCompleted(deferred.resolve); //Waiting for the event

  return deferred.promise();
}

Full example on JSBin

A Promise is a object that has a done event. A Deferred is an object that has a Promise and a resolve() method that will raise the done event on that Promise. If you first call resolve() on the Deferred and then register a handler for the done the handler is immediately called. So you won't miss the event even if you were slower than the asynchronous load request.

But: If your model could not even been set on the component/core when your view initializes you have a severe problem as there is no such thing as a modelChanged event. I would recommend to create a empty model and assign it to the component in the components init-method and then use loadData() on that model.