I've setup datatables.net with server side processing on a MVC application using the DataTables.Aspnet.Core & DataTables.AspNet.WebApi2 nugets. All works well and the data gets loaded and displayed fine.
If there is an issue on the server side I catch the exception and return a result containing my custom error message:
// IDataTablesRequest tableRequest
return new DataTablesJsonResult(Response.Create(tableRequest, "my custom error message"), Request);
On the client side I've registered to the error event as well:
$.fn.dataTable.ext.errMode = 'none';
this.$dataTable.on('error.dt', this.onDataTableError.bind(this));
This also works fine, I can parse the response and check for my custom message.
Now the issue: After handling the error I always get the dreaded Uncaught TypeError: Cannot read property 'length' of undefined I assume this is the case because I don't send any data to the client?
How can I prevent this error?
I could not manage to fix this on the server side by adding an empty dataset as this would not be passed with the json.
What I ended up doing is ensuring there is always a data array on the client side:
// register to ajax request event
this.$dataTable.on('xhr.dt', this.afterAjax.bind(this));
// set empty array to make sure we have no issue
// with null references on data.length for loop
afterAjax(event: JQueryEventObject, settings: any, payload: any, response: any): void {
payload.data = payload.data || [];
}
Related
in my project I use some cloud functions: one of them sets custom claims, it works properly, I have a second function that when fired should write some data on the realtime Db,but once is fired I get a CORS Error; this is the faulty function:
exports.insertUser = functions.https.onCall((data)=>{
const db = admin.database();
const reference = "userProfile";
return db.ref(reference).push(data.user).then(()=>{
return {message: "utente inserito"};
}).catch((error)=>{
return error;
})
});
this is the error that I get:
Access to fetch at 'https://us-central1-trasportostudenti-
bc19c.cloudfunctions.net/insertUser' from origin 'http://localhost:8100' has been blocked by CORS policy: Response to preflight request doesn't pass access control check
firebase's log states that the problem is in my code; any suggestions to fix this error?
We upload a document from SAPUI5 to our SAP System using the CREATE_STREAM Method of the oData Service in ABAP. The creation of the document works fine.
What we would like to achieve is to get the response back to SAPUI5. Especially when there is an error during the creation of the document in the backend.
In Frontend we use the uploadSet Control.
...oUploadSet.uploadItem(oItem);
In the Backend we create a message with
...lo_message_container->add_message( iv_msg_type = /iwbep/cl_cos_logger=>error
iv_msg_number = '018'
iv_msg_id = lv_msg_id
iv_add_to_response_header = abap_true
)....
We can find the created message in the error protocol of our gateway server (/IWFND/ERROR_LOG). But how can this message be retrieved in SAPUI5 and used in the MessageManger Control?
We tried the onUploadCompleted Control but we can't find any response data there.
Can somebody explain how the response or a message header from the CREAT_STREAM method can be used in SAPUI5?
The "new" UploadSet control is kinda half-baked imo. The response will get lost in some internal method. This internal method will then trigger onUploadCompleted and you get nothing but useless information.
Lucky for us we can easily overwrite this internal stuff. UploadSet has an aggregation Uploader. We have to provide our own Uploader. Problem solved. Here is the line that needs to be modified.
sap.ui.define([
"sap/m/upload/Uploader",
...
], function (Uploader, ...) {
return Uploader.extend("my.custom.control.Uploader", {
uploadItem: function (oItem, aHeaders) {
// beginning of the method. take it from the official sources
oXhr.onreadystatechange = function () {
const oHandler = that._mRequestHandlers[oItem.getId()];
if (this.readyState === window.XMLHttpRequest.DONE && !oHandler.aborted) {
// we need to return the xhr object. it contains the response!
that.fireUploadCompleted({ item: oItem, xhr: oXhr });
}
};
// .. rest of the method
}
});
});
Use it like this
<mvc:View xmlns:custom="my.custom.control" ....>
<UploadSet items="....">
.....
<uploader>
<custom:Uploader uploadUrl="......"
uploadCompleted=".onUploadCompleted"
uploadStarted=".onUploadStarted" />
</uploader>
</UploadSet>
Edit: Your own uploader also means implementing your own event handlers (uploadAborted, uploadCompleted, uploadProgressed, uploadStarted). See the official documentation for more information about the events.
I tried to update one entity in my angularjs client using breezejs library. After calling saveChanges(), it can actually save back in the server and fetched on the client. However, the server did not return the response back. The saveResult.entities is undefined and pop up an error for me. When I took a look at the docs, it mentions 'Some service APIs do not return information about every saved entity. If your server doesn't return such information, you should add the pre-save, cached entity to saveResult.entities yourself'. Could anyone provide an example of how to do this?
This is the code when i am trying to do an update.
manager.saveChanges(entitiesToSave, null, (saveResult) => {
const savedRes = saveResult;
savedRes.entities = entitiesToSave;
return savedRes;
}).then(saveSucceeded);
On the server, you would need to construct the response for an update similar to the way it is for a create:
response.setContent(...); // entities
response.setStatusCode(HttpStatusCode.OK.getStatusCode());
response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString());
event.respondWith(caches.match(event.request).then(function (response) {
if (response) {
return response;
}
//return fetch(event.reuqest, { credentials: 'include' });
//event.respondWith(fetch(event.request, { credentials: 'include' }));
}));
This is a common code for handling request via serviceworkers , if the url is in cache then return cache response or fetch it from server .
But my doubt is regarding the 2 commented lines , we need to use one of them for fetching the response .
My doubt is, when i use event.respondWith(fetch(event.request, { credentials: 'include' for fetching a page , i get the following error
DOMException: Failed to execute 'respondWith' on 'FetchEvent': The fetch event has already been responded to.
But the page is finally rendered , definitely browser is finally fetching the response , but when i use sam for fetching an image , i get the same error and on top of that the image is not fetched .
if i use the second option that return fetch(event.reuqest, { credentials: 'include' }); , then it works fine for both image as well as page.
I am not able to figure out what is the reason of that error , and also why it is behaving differently for file and page .
My another doubt is , do i actually need the credential parameter here ,i added it because most of the implementations i saw in web have used it,but what i have observed is that the request object already has a credential property with it , now it is not always
include
sometime it is
same-origin
too.
So could it happen that i am actually overriding the actual credential value by adding it .If that is not the case , then there is no difference in including it or not.It does not matter .
But if it is other way around , then we should not overwrite the credential value, which can have bad side effects.
You already have a call to event.respondWith, you don't need to call it twice.
Your first call is going to use the promise returned by:
caches.match(event.request).then(function(response) {
if (response) {
return response;
}
return fetch(event.reuqest, { credentials: 'include' });
})
This promise resolves to:
response, if the request is in the cache;
the promise returned by the call to fetch, otherwise.
The promise returned by fetch will resolve to a response, which is then going to be used by respondWith.
I perform an update via my OData service like this:
oModel.create('/Carriers', oEntry, null, function () {
oModel.refresh();
sap.m.MessageBox.show("Saved", sap.m.MesESS);
}, function (err) {
var message = $(err.response.body).find('message').first().text();
sap.m.MessageBox.show(message, sap.m.MessageBox.Icon.ERROR);
});
If I get an error message in the response I am unable to display the message text.
I create the error like this:
CALL METHOD lo_message_container->add_message_text_only
EXPORTING
iv_msg_type = 'E'
iv_msg_text = msg_text.
RAISE EXCEPTION TYPE /iwbep/cx_mgw_busi_exception
EXPORTING
message_container = lo_message_container.
ENDIF.
The err.response.body looks like this:
"{"error":{"code":"SY/530","message":{"lang":"en","value":"This
is the error I am trying to show)"},
"innererror":{"transactionid":"B20B61E5143BF10E92CB000C29D28D3A","timestamp":"20150922092421.4230000","Error_Resolution":{"SAP_Transaction":"Run
transaction /IWFND/ERROR_LOG on SAP NW Gateway hub system and search
for entries with the timestamp above for more details","SAP_Note":"See
SAP Note 1797736 for error analysis
(https://service.sap.com/sap/support/notes/1797736)"},"errordetails":[{"code":"","message":"This
is the error I am trying to show
","propertyref":"","severity":"error","target":""},{"code":"/IWBEP/CX_MGW_BUSI_EXCEPTION","message":"","propertyref":"","severity":"error","target":""}]}}}"
I was trying this but it does not work...
var message = $(err.response.body).find('message').first().text();
sap.m.MessageBox.show(message, sap.m.MessageBox.Icon.ERROR);
It looks like your error is mistaking JSON for a DOM object.
jQuery (the $-sign function) is meant to select DOM elements with the tag name, classes or the id.
To find the right key in an JSON structure, you can use normal JavaScript dot- or brackets-notation:
var message = err.response.body.error.message.value;