on 02-10-2017 11:04 AM
How can I use a model that was loaded by an async AJAX request in the UI?
What is the approach to load the model and even where?
I've tried to load the model in the Component.js (based on the QuickStartApplication template). Doesn't work. Because the request grabs data from another server it has to be async anyway. The AJAX call returns the data but I can't wait for it in neither in the component.js nor in the controller nor in the model.js.
My model.js including the async call looks like:
sap.ui.define([
"sap/ui/model/json/JSONModel"
], function(JSONModel) {
"use strict";
function ajaxCallToCMISRepository(callbackResult) {
jQuery.sap.log.info("Entering ajaxCallToCMISRepository");
var resultObjects = "({})";
var repoUser = "admin";
var repoPass = "admin";
var repoURL = "https://myserver:8443/cmis/root";
jQuery.sap.log.info("Load JSON from Repository " + repoURL);
var method = "GET";
jQuery.sap.log.info("AJAX call to: " + repoURL);
var dfd = new $.Deferred();
$.ajax({
type: method,
url: repoURL,
async: false,
data: "{}",
crossDomain: true,
dataType: "jsonp",
beforeSend: function (xhr){
xhr.withCredentials = true;
xhr.setRequestHeader("Authorization", "Basic " + btoa(repoUser + ":" + repoPass));
},
success:function(data) {
callbackResult(data);
},
error : function (xhr, status, error) {
jQuery.sap.log.info("ERROR xhr: " + xhr);
jQuery.sap.log.info("ERROR status: " + status);
jQuery.sap.log.info("ERROR error: " + error);
var keys = $.map(xhr, function(item, key) {
jQuery.sap.log.info("!!!!!!! " + key + " ==> " + item);
});
}
});
//jQuery.sap.log.info("Return resultObjects: " + resultObjects);
//return resultObjects;
}
return {
loadRepositoryModel: function() {
jQuery.sap.log.info("Entering loadRepositoryModel in model.js)");
var resultJSON = "";
ajaxCallToCMISRepository(function(data) {
resultJSON = data;
//resultJSON = getFolderNamesFromRepository(resultJSON["objects"]);
var oModel = new JSONModel(resultJSON);
oModel.setData(resultJSON);
oModel.setDefaultBindingMode(sap.ui.model.BindingMode.OneWay);
jQuery.sap.log.info("RETURN from loadRepositoryModel()!" + resultJSON.getJSON());
return oModel;
});
//return resultJSON;
}
};
});
The related part in the Component.js is:
init: function() {
// call the base component's init function
UIComponent.prototype.init.apply(this, arguments);
var cmisModel = new JSONModel(models.loadRepositoryModel());
this.setModel(cmisModel, "repoModel");
jQuery.sap.log.info("cmisModel -> " + cmisModel.getJSON());
But while the AJAX returns the model, meaning the log of resultJSON.getJSON() in the model.js returns the result, the cmisModel.getJSON() in the component.js is always empty because it does not wait.
What is the best way to load and finally to display async data in the UI?
Hi,
This should not be complicated, use data binding and set the data to the model when you get it from the server. Here's an example: http://plnkr.co/edit/A5NUMbGa1fOz03dZ8qIJ?p=preview
Cheers,
Pierre
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi,
thanks, but it's still not working... tried it now with a simpler model but still dont know, how to bin the model within JavaScript to an ObjectListItem?
my component.js
init: function() {
UIComponent.prototype.init.apply(this, arguments);
sap.ui.getCore().setModel(new JSONModel({}), "activeUser");
models.setCurrentUserModel();
}
my model.js
return {
setCurrentUserModel: function() {
var repoUser = "myuser";
var repoPass = "mypass";
var repoURL = "https://our.company.com:8443/api/user";
$.ajax({
type: "GET",
url: repoURL,
async: true,
crossDomain: true,
beforeSend: function (xhr){
xhr.withCredentials = true;
xhr.setRequestHeader("Authorization", "Basic " + btoa(repoUser + ":" + repoPass));
},
success:function(data) {
var oModel = new JSONModel();
oModel.setData(data);
oModel.setDefaultBindingMode(sap.ui.model.BindingMode.TwoWay);
sap.ui.getCore().setModel(oModel, "activeUser");
},
error : function (xhr, status, error) {
jQuery.sap.log.info("ERROR xhr: " + xhr);
jQuery.sap.log.info("ERROR status: " + status);
jQuery.sap.log.info("ERROR error: " + error);
}
});
}
};
The JSON that is returned has the following format, its just one entry:
{"id":1001,"firstName":"Henry","lastName":"Myers","email":"h.myers@company.com","externalId":null, "authorization: [ {...}, {...}]}
All I want to display in the sap.m.ObjectListItem is the "firstName" and the "lastName" as title information. So, I tried to read it in the init() method of the controller view:
return Controller.extend("QuickstartApplication1.controller.View1", {
onInit : function () {
var userObjectListItemTile = this.byId("tileUserAccount"); //this does exists and is of type ObjectListItem, like: <ObjectListItem title="User Account" intro="User Account" icon="sap-icon://account" id="tileUserAccount" activeIcon="sap-icon://account"/>
userObjectListItemTile.bindProperty("title", "acitivUser>/firstName");
}
});
Nothing happens, even the model is loaded? Any thought what goes wrong?
Thanks!
Well maybe you should start with the tutorial if you don't know how to use data binding: https://sapui5.hana.ondemand.com/#docs/guide/bf71375454654b44af01379a3c3a6273.html
binding only need model, not the data.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Tried the $.Deferred(); approach along with the attachRequestCompleted event. Looks like this works only fine for models loaded with .loadData(...). But I have a async request (from another domain) and I'm using the function setData(ajaxResultJSON) to fill the model. With that the attachRequestCompleted event is not fired.
This is an example that I found, it does exactly what I need but it uses the .loadData() function: https://jsbin.com/miripajozu/2/edit?html,js,console,output
The issue is, that the model is not available at this time, because it is still loading. So, having the $.Deferred(); approach in my controller, the model is undefined at this time and therefore the .attachRequestCompleted() fails... and the wait does not work at all.
Next try was to instantiate the model in the controller before (according to the example above), setting an empty model, like:
sap.ui.getCore().setModel(new JSONModel(),"cmisModel");
Having that, the $.Deferred(); approach does not work either, because attachRequestCompleted() is always true for the promise. It is not fired again when the async requests updates the data with setData().
This is the code I tried in my controller.js:
var cmisModel = sap.ui.getCore().getModel("cmisModel");
var remoteCheck = this.getPromise(cmisModel,"/objects");
$.when(remoteCheck).done(function(){
jQuery.sap.log.info("Model loaded!");
this.byId("myRepoTable").setModel(cmisModel, "cmisModel");
}.bind(this));
The getPromise function:
getPromise : function (oModel, pathToTestForData){
jQuery.sap.log.info("IN: getPromise, " + oModel + ", " + pathToTestForData);
var deferred = $.Deferred();
if (oModel.getProperty(pathToTestForData)){
jQuery.sap.log.info("ok");
deferred.resolve(); //Data already loaded
} else {
jQuery.sap.log.info("wait");
oModel.attachRequestCompleted(deferred.resolve()); //Waiting for the event
}
jQuery.sap.log.info("OUT: getPromise!");
return deferred.promise();
}
Any suggestions how I can solve it?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Thank you for the answer. But even if I try to set the model in the success function, because of the ASYNC call the rest of the model including the UI has been already loaded before the AJAX call has finished. So I still facing the same issue.
success:function(data) {
sap.ui.getCore().setModel(data, "cmisModel");
Maybe, I have to refresh the table after loading? But within the success I don't have the controller available. What is the best way to do that?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
normally in this case we can pass component instance to model.js so that model can be set on Component
Use below code in Component.js
init: function(){
UIComponent.prototype.init.apply(this, arguments);
models.loadRepositoryModel(this); //pass component instance to method in models
}
//Below code for success method in loadRepositoryModel
loadRepositoryModel: function(Component) { //Component reference passed to method
success:function(data) {
Component.setModel(data, "cmisModel");
}
}
When using AJAX calls or ODATA aggregation bindings its better to use promises to notify that data load is completed.
In your case 'model.js' contains the function 'success' indicating that data is loaded from AJAX call, in this promise function you can set the model 'cisModel'
or
Raise an event from the promise function and catch the same in 'Component.js', in the event handler set the model 'cisModel'
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
91 | |
10 | |
10 | |
9 | |
9 | |
7 | |
6 | |
5 | |
5 | |
4 |
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.