custom webapi function binding to store extjs grid - extjs4.2

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

Related

How to call script include from the client script service-now without GlideAjax

The common process we follow today to get the data on client script:
OnChange client script:
function onChange(control, oldValue, newValue, isLoading, isTemplate) {
if (isLoading || newValue === '') {
return;
}
var user = g_form.getValue('u_user');
//Call script include
var ga = new GlideAjax('global.sampleUtils'); //Scriptinclude
ga.addParam('sysparm_name', 'getUserDetails'); //Method
ga.addParam('userId',user); //Parameters
ga.getXMLAnswer(getResponse);
function getResponse(response){
console.log(response);
var res = JSON.parse(response);
console.log(res);
g_form.setValue('u_phone',res.mobile_phone);
g_form.setValue('u_email',res.email);
}
}
Script include:
var sampleUtils = Class.create();
sampleUtils.prototype = Object.extendsObject(AbstractAjaxProcessor, {
getUserDetails: function(){ //Function
var userId = this.getParameter('userId'); //Params
obj = {};
var grSysUser = new GlideRecord('sys_user');
if (grSysUser.get(userId)) {
obj.mobile_phone = grSysUser.getValue('mobile_phone');
obj.email = grSysUser.getValue('email');
}
gs.addInfoMessage(obj+JSON.stringify(obj));
return JSON.stringify(obj);
},
type: 'sampleUtils'
});
DEMO Link: https://youtu.be/nNUsfglmj_M
As an alternative to glideAjax you can EfficientGlideRecord
new EfficientGlideRecord('sys_user')
.addQuery('sys_id', newValue) //On Change client script, we will get sys_id of user in newValue variable
.addField('mobile_phone', true) //Get display value
.query(function (egrSysUser) {
if(egrSysUser.next()) {
g_form.setValue('phone', egrSysUser.getDisplayValue('mobile_phone'));
}
});
What is EfficientGlideRecord?
EfficientGlideRecord is the best alternate way to use GlideAjax.
It is a client-side API class from which you can perform asynchronous client-side GlideRecord-style queries while maximizing performance.
Benefits:
Low code configuration with Huge performance improvement.
No need to worry about security loopholes, because it enforces ACLs.
No more concerns about creating new client callable script includes and maintaining
the logic there.
Dependencies:
To use the EfficientGlideRecord we need to commit the attached update-set or find the latest version from the given link https://github.com/thisnameissoclever/ServiceNow-EfficientGlideRecord/releases.
Add the package to Portal record -> JS Includes.
and that's it, and you are good at using the EfficientGlideRecord syntax.
To know more about EfficientGlideRecord, Refer the below link(s):
https://snprotips.com/efficientgliderecord

How to pass a key field as variable instead of hard-coded key value to OData operation?

I am calling the GetEntity OData read method from the SAP UI5 view controller and passing a key value in the request URL. I am getting the proper response from the back-end when I hardcode the key value.
However, when I try to pass the key value dynamically in a variable by appending it to the URL, it doesn't work. I get the following error
HTTP request failed 404
In below code, sGrant is the variable and it doesn't work. But if I replace the variable name with its value hard-coded in below code, for example, in the read method like this: "/GrantMasterSet('TY560003')", then it works:
var sGrant = this.byId("grantNbr").getValue();
var oMod = this.getOwnerComponent().getModel();
oMod.read("/GrantMasterSet('sGrant')", {
success: function(oData) {
var oJsonModel = new JSONModel();
oJsonModel.setData(oData);
this.getView().setModel(oJsonModel);
}.bind(this),
error: function(oError) {
MessageToast.show("Read Failed");
}
});
UI5 has a method to generate the right URI for you, no matter what is the data type of the key of your entity type.
The method is createKey of the sap.ui.model.odata.v2.ODataModel class. See its documentation
Inside your controller, use the following source code.
onInit: function () {
var oRouter = this.getOwnerComponent().getRouter();
oRouter.getRoute("routeName").attachPatternMatched( this.onPatternMatched , this );
},
onPatternMatched: function(oEvent){
var oParameters = oEvent.getParameters();
var oArguments = oParameters.arguments; // is not a function - without ()
var sKey = oArguments.id; // route parameter passed when using navTo
var oDataModel = this.getView().getModel(); // v2.ODataModel
oDataModel.metadataLoaded().then(function() {
var sPath = oDataModel.createKey("EntitySet", { Key: sKey });
this.getView().bindElement("/" + sPath);
}.bind(this)
);
}
Usually this is necessary in details pages, in order to apply element binding to a page. As the createKey method relies on the $metadata of your service, you must make sure that it is already loaded in your app. This can be achieved by using method metadataLoaded, provided in the snippet as well.
You should concatenate the variable to the rest of the string, like this:
oMod.read("/GrantMasterSet('" + sGrant + "')", {
Or, you can use a template literal, which comes down to the same thing (notice the backtics):
oMod.read(`/GrantMasterSet('${sGrant}')`, {
You should escape 'sGrant' so it can be evaluated.
It should be something like that :
var sGrant = this.byId("grantNbr").getValue();
var oMod = this.getOwnerComponent().getModel();
oMod.read("/GrantMasterSet("+sGrant+")", {
success: function(oData) {
var oJsonModel = new sap.ui.model.json.JSONModel();
oJsonModel.setData(oData);
this.getView().setModel(oJsonModel);
}.bind(this),
error: function(oError) {
MessageToast.show("Read Failed");
}
});

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);

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

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.

Loopback REST connector, data mapping response to model?

I've setup a simple "product" model (ie {id:"string","name":string, etc}) and setup a datasource using the REST connector to a remote URL that returns a JSON blob containing dozens of fields, how do I go about mapping the fields from the remote response to my local model? Whenever I execute my method I'm getting back the raw response from the remote....I was expecting, at a minimum, to get back an empty version of my model.
I'm pretty sure you will have to override the find() method on your model and perform this mapping work manually.
Something like this:
module.exports = function(app) {
var Product = app.models.Product;
var find = Product.find;
Product.find = function(filter, cb) {
// invoke the default method
find.call(Product, function(err, original_results) {
var results = {}; // a placeholder for your expected results
results.name = original_results.id;
results.name = original_results.name;
results.description = original_results.long_description;
// and so on
cb(null, results)
});
}
}