JSONModel: How to merge with existing data when calling "loadData" - sapui5

I have the following coding in my SAP UI5 application Controller:
var myView = this.getView();
var data1 = { "myDate": new Date() };
oModel.loadData("products.json");
oModel.setData(data1);
myView.setModel(oModel);
Where products.json - just a simple data for the table on the screen.
And I can see only products.json data on the screen as a result, and myDate with empty value inside oModel (checked in debug).
In case I comment loadData string, myDate value is on the screen and looks good.
How I can use them together? What is the best practice for such cases?

The model's loadData is an asynchronous process, so it will update the model after you have set it synchronously with data1.
Also, setData() will wipe everything already in the model, so better use setProperty and update only a specific node in your model.
You should add the static data once you have loaded it from file:
oModel.attachRequestCompleted(function() {
oModel.setProperty("/myExtraData", data1);
});
Your added date is then available via /myExtraData/myData

Merge new data with existing one with bMerge parameter of setData().
oModel.loadData("products.json");
var data1 = {
"myDate": new Date()
};
oModel.attachRequestCompleted(function() {
oModel.setData(data1, true);
});

The API loadData has also a bMerge option.
oModel.setData({ myDate: new Date() });
oModel.loadData("products.json", null, true, "GET", /*bMerge*/true);
// Merged results:
{
myDate: /*date object*/,
produces: [/*...*/]
}
No need to register an event handler for requestCompleted.

Related

What is the difference between setJSON, setData and loadData?

This is regarding the mentioned methods of sap.ui.model.json.JSONModel in SAPUI5:
setJSON
setData
loadData
What is the difference between these 3 methods? When do we use these methods and can we use more than 1 of them for the same purpose?
Have a look at the well documented API Reference for JSONModel.
In summary (from SAP Documentation):
setData: Sets the data, passed as a JS object tree, to the model.
e.g
var data = {
"ProductCollection": [{
"titleId": 0,
"Name": "Olayinka O",
"ProductId": "001",
"chartValue": 75,
"ProductPicUrl": "sap-icon://competitor"
}]
};
var oModel = new sap.ui.model.json.JSONModel(data);
//OR
var oModel = new sap.ui.model.json.JSONModel();
oModel.setData(data);
/*setdata, could also be a odata url in json format*/
loadData:
Load JSON-encoded data from the server using a GET HTTP request and store the resulting JSON data in the model. Note: Due to browser security restrictions, most "Ajax" requests are subject to the same origin policy, the request can not successfully retrieve data from a different domain, subdomain, or protocol.
e.g. you can use this to load/GET changes to the data/model and automatically updates the view if that specific model has being binded by reloading the url. If you use load, you don't need the other two in my opinion and loadData with not work on local json data.
var sURL = "https://cors-anywhere.herokuapp.com/https://services.odata.org/V3/Northwind/Northwind.svc/Products?$format=json";
var oModel = new sap.ui.model.json.JSONModel();
//if called in setInterval, all changes in the backend will be updated in the view if binded in this case every second
setInterval(oModel.loadData(sURL, true), 1000);
setJSON :
Sets the data, passed as a string in JSON format, to the model.
i.e. Same as Set Data but strict JSON
Luckily, the source code of UI5 is quite readable and often the better documentation than most of the API descriptions. Here is what each one of the APIs does basically:
setJSON
"Parse the JSON text and call setData"
JSONModel.prototype.setJSON = function(sJSON, bMerge) {
var oJSONData;
try {
oJSONData = jQuery.parseJSON(sJSON);
this.setData(oJSONData, bMerge);
} catch (e) {
// ...
}
};
Source
setData
"Store the data and notify all dependent bindings (checkUpdate)"
JSONModel.prototype.setData = function(oData/*plain JS object*/, bMerge){
if (bMerge) {
this.oData = /* merge with existing data */;
} else {
this.oData = oData;
} // ...
this.checkUpdate(); // notifies dependent bindings
};
Source
loadData
"Load data from the given remote URL and call setData" --> Please check the source here.
In short, they all call setData at some point.
Which API to call in which situation depends on in which format you have the data available.
The data are in JSON text --> setJSON
The data are somewhere else --> loadData
I already have the data in JS object / array ---> setData
setData
You have a JavaScript object and want to use this data as your model
const oJSONData = {
data: {
id: 4,
first_name: "Eve",
last_name: "Holt",
avatar: "https://s3.amazonaws.com/uifaces/faces/twitter/marcoramires/128.jpg"
}
};
oJSONModel.setData(oData);
setJSON
You have a String that when parsed represents a JavaScript object and want to use this data as your model
const sJSONData = '{"data":{"id":4,"first_name":"Eve","last_name":"Holt","avatar":"https://s3.amazonaws.com/uifaces/faces/twitter/marcoramires/128.jpg"}}';
oJSONModel.setJSON(sJSONData);
loadData
You want to access a remote API which returns data as JSON and want to use this data as your model
const sURL = "https://reqres.in/api/users/4";
oJSONModel.loadData(sURL);

attachRequestCompleted errors out in init()

I am using following snippet which I am using in init function. My oAppModel is getting loaded with the data. However, oAppModel.attachRequestCompleted() does not get executed even. I have tried to pass oEvent also, but when I use oEvent, it says oEvent is not defined.
var oAppModel = new sap.ui.model.json.JSONModel();
oAppModel.loadData(oData);
//attach
oAppModel.attachRequestCompleted(function(){
//get value:
var soldto = oAppModel.getProperty("/SoldTo/0/Name");
});
Could you please help ?
you are loading data (oData) into the model hence not HTTP(s) request is made. therefore, requestCompleted event is not fired.
it will fire if you do this.
var oAppModel = new sap.ui.model.json.JSONModel();

how to capture the data sent by alloy ui io request in serveresource method?

Getting blank values for title and description in serveResource method.Is this the right way to send the parameters from io request?
After inserting blank values in database I have to reload the page to see the inserted values?So io-request is not ajax request?
<aui:script use="aui-base">
A.one('#<portlet:namespace/>save').on('click', function(event) {
var A = AUI();
var title=A.one('#<portlet:namespace/>title').val();
alert(title);
var description=A.one('#<portlet:namespace/>description');
var url = '<%= newJob.toString() %>';
A.io.request(
url,
{
method:'POST',
data: {
<portlet:namespace />title: title,
<portlet:namespace />description: description,
},
}
['aui-io-deprecated']
);
Liferay.Util.getOpener().<portlet:namespace/>closePopup('<portlet:namespace/>dialog');
});
AUI's io request is ajax request only.
You can get parameters in serveResource method using code below:
ParamUtil.get(resourceRequest, "NAMEOFPARAMETER");
Modify your javascript function and provide data attribute as below:
data: {
'<portlet:namespace />title': title,
'<portlet:namespace />description': description,
}
I assume both title and description are textfields. If so, description is missing a .val() call, or more appropriately, .get('value'). I didn't use a dialog/modal in my source, but the overall approach should be the same.
<script>
AUI().use('aui-base', 'aui-io-request', function(A){
A.one('#<portlet:namespace />save').on('click', function(event) {
var title= A.one('#<portlet:namespace />title').get('value');
var description=A.one('#<portlet:namespace />description').get('value');
var url = '<%=myResourceURL.toString()%>';
A.io.request(url,
{
method:'POST',
data: {
title: title,
description: description,
},
});
});
});
</script>
I'm still relatively new to Liferay and have had trouble with this as well. I've noticed that the data parameters are not in the parametersMap of the default ResourceRequest, as you have stated. Out of curiosity, I decided to use
UploadPortletRequest req = PortalUtil.getUploadPortletRequest(resourceRequest);
in the serveResource method and check it's parametersMap. The title and description parameters are available therein. I'm still learning where and how to access data from Liferay objects, but it would seem that for the UploadPortletRequest to have the data, it would be plucked from somewhere within the default ResourceRequest ... where still remains elusive to me.
After inserting blank values in database I have to reload the page to see the inserted values?
You have to reload the page because a resource action does not trigger a page refresh. If you are manipulating data that you want reflected in some other "view" you'll need to configure the appropriate communication or use one of the other available url types that does trigger the doView method of your other "view".

custom webapi function binding to store extjs grid

I need help to bind data returned by a custom webapi function. Say my webapi function calling syntax is like below:
var filter = {<some conditions here>};
Myapp.systemcontroller.Getdata(filter).then(function(result){
--- this result contain my data and total record
});
How can I bind this function to the store proxy and then bind it to a grid?
Any help would be greatly appreciated.
You can use different way to add the data to store. Its depend on your data structure(array or object).
grid.getStore.add(model) -ref:
http://docs.sencha.com/extjs/4.2.1/#!/api/Ext.data.Store
grid.getStore.loadData(data,[append]) - ref:
http://docs.sencha.com/extjs/4.2.1/#!/api/Ext.data.Store-method-loadData
grid.getStore.loadRawData(data,[append]) - ref:
http://docs.sencha.com/extjs/4.2.1/#!/api/Ext.data.Store-method-loadRawData
grid.getStore.loadRecords(records,options) - ref:
http://docs.sencha.com/extjs/4.2.1/#!/api/Ext.data.Store-method-loadRecords
In your case, you can use loadRecords() or add()
The problem has been fixed. I m not using any proxy in my store.. I m using the above api to retrieve the data and bind it to store using loadData method. Then I will set the totalProperty of my toolbar as well
-- on load
Myapp.systemcontroller.Getdata(f).then(function (data) {
gridstore.loadData(data.Items);
gridstore.totalCount = data.TotalNumber;
var pgTb = Ext.getCmp('DataListPgTb');
pgTb.onLoad();
me.getLogList().setLoading(false);
});
Then in the toolbarchange event
toolBarChange: function (tbar, pageData, eOpts) {
var pageSize = PrIns.getApplication().Configuration.PageSize;
var me = this;
me.getLogList().setLoading(true);
var f = Ext.create(MyApp.webapi.filter.LogFilter', { pageIndex: pageData, pageSize: pageSize, orderBy: 'Ascending' });
var gridstore = this.getLogList().getStore();
Myapp.systemcontroller.Getdata(f).then(function (data) {
gridstore.loadData(data.Items);
gridstore.totalCount = data.TotalNumber;
gridstore.currentPage = pageData;
var pgTb = Ext.getCmp('DataListPgTb');
pgTb.onLoad();
me.getLogList().setLoading(false);
});
return false;
},
return false will prevent us from calling the proxy

Ember - clear form after submitting

I created very simple Ember app, using Ember Data. There is one form where the user creates the entity and submits. It's in BandsNewView (created automatically by Ember), controlled by BandsNewController:
App.BandsNewController = Ember.Controller.extend({
cancel: function() {
this.transitionTo('bands');
},
save: function() {
App.Band.createRecord(this);
this.get('store').commit();
this.set('name');
this.set('description');
this.transitionTo('bands');
}
});
I wonder whether there is simplier solution to "clean up" (i.e empty) the form after saving new Band entity? Can I say something like this.set(), which would empty all the fields? Or is my approach essentially wrong and should I do it completely differently?
The pattern that I've been enjoying is creating and destroying the object on enter and exit of the route itself.
App.BandsNewRoute = Ember.Route.extend({
model: function(params) {
return App.Band.createRecord({});
},
save: function() {
this.get('currentModel.store').commit();
return this.transitionTo('bands');
},
exit: function() {
var model = this.get('currentModel');
if (model.get("isNew") && !model.get("isSaving")) {
return model.get('transaction').rollback();
}
}
});
As you can see, it makes the exit function a little more complex, but it will be exactly the same for every object creation route, so you can factor it out. Now your templates can just bind straight to the model's properties and the model will be saved on save, or rolled back on exit (which will clear the form)
If you are planning on possibly changing other data models and not saving them, or have unsaved models, a way to safely clear the model away is to put it in it's own transaction. I only tend to use this though for objects that are not the main focus of my current flow.
App.BandsNewRoute = Ember.Route.extend({
model: function(params) {
var transaction = this.get('store').transaction();
return transaction.createRecord(App.Band, {})
}
});
Everything else can stay the same.