CefSharp - Get result of AJAX request - javascript

I am really new to CefSharps Chromium browser and have difficulty figuring out how to get the result of a jquery ajax request.
My first attempt was to pass my AJAX requesto to EvaluateScriptAsync. In fact the script works. It does exactly what I want, but I do not get any results/status codes, because my Cef-Task does not wait until AJAX has completed its work.
Here an example (just a sample code):
var tasks = pdBrowser.EvaluateScriptAsync(#"
(function(){
$.ajax({
type: ""POST"",
dataType: ""json"",
cache: false,
url: ""_resources/php/ajaxRequests.php"",
async: false,
data: {
action: ""insertCrossPlatform"",
type: """",
values: JSON.stringify(""foo bar"")
},
success: function(response) {
if (typeof response === 'string' && response.substring(0, 5) == ""ERROR"")
{
return response;
}
else
{
//pageReload();
return ""OK"";
}
},
error: function(xhr, textStatus, errorThrown) {
return errorThrown + ""\n"" + xhr.responseText;
},
complete: function() {
return ""COMPLETE"";
}
});
})();", null);
tasks.ContinueWith(t =>
{
if (!t.IsFaulted)
{
var response = t.Result;
if (response.Success)
{
if (response.Result != null)
{
MessageBox.Show(response.Result.ToString());
}
}
else
{
MessageBox.Show(response.Message, "Ein Fehler ist aufgetreten", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
}
}, TaskScheduler.Default);
Afterwards I have read that there is a SchemeHandler, but I do not properly understand how to implement it. Can anyone help me out?
Thanks in advance.

Firstly SchemeHandler is unlikely to be suitable in this scenario, you would typically implement a SchemeHandler when your providing the response.
Most people choose to bind an object, and call a method on their bound object when they wish to communicate with the parent application. See the FAQ for an example. https://github.com/cefsharp/CefSharp/wiki/Frequently-asked-questions#3-how-do-you-expose-a-net-class-to-javascript
With 49.0.0 you can implement ResponseFilter to gain access to the underlying response buffer, it's complex and not well documented, so if your not comfortable digging through reference C++ code then this option isn't for you. Here's a reference https://github.com/cefsharp/CefSharp/blob/cefsharp/49/CefSharp.Example/Filters/PassThruResponseFilter.cs#L17

Something that I did was create an element on the page through javascript with an ID that is the response of the ajax call. So for example, when you make an ajax call assign an ID to the ajax call.
When the ajax call returns, write an element on the page with the pre-assigned id and callback information. Then you can just use cefsharp to read the element content from the page and this will be your callback information.
var myDivElement =document.getElementById('textareaInfo');
if( myDivElement === null)
{
var input = document.createElement('textarea');
input.id = "textareaInfo";
input.value = "Test"
input.rows="4";
input.cols="50";
input.style="height:100%;width:900px;"
var dom = document.getElementsByClassName("page-body")[0];
dom.insertAdjacentElement('afterbegin', input)
}
Then later with ajax
var root = 'https://jsonplaceholder.typicode.com';
var _holder = callbackObj;
callbackObj.showMessage(""ajax"");
$.ajax({
url: root + '/posts/1',
contentType: 'application/json; charset=utf-8',
method: 'GET',
complete: function(data){
},
success: function(response) {
$(#'textareaInfo').value(response);
}
}).then(function(data) {
callbackObj.showMessage(data);
});
Then read the texarea from cefsharp in c#
chromeBrowser.GetMainFrame().EvaluateScriptAsync(function()...$(textareaInfo).value).Result

You can use PostMessage javascript method to notify .NET application:
CefSharp.PostMessage('Your data Here');
Here is .NET code example for headless browser:
var browser = new ChromiumWebBrowser("", null, RequestContext);
browser.JavascriptMessageReceived += (sender, e) =>
{
if ((string)e.Message.notificationid == "notification1")
{
// Your processing code goes here
}
};
browser.Load(destinationUrl);
browser.ExecuteScriptAsync("(function() { ... ; CefSharp.PostMessage({data: data, notificationid: 'notification1'});})()");

Related

Best way to call function inside of another function JavaScript/JQuery?

I have built function that checks if record exist in local storage, if not trigger ajax call to get the data. Once data is returned I set the data in local storage. After this function completes I have to pass the data to another function that will feed the data in the form. I'm wondering what is the best practice now days to achieve this? I see more object oriented JavaScript now days and I'm wondering if any of OOP methods can be applied in this case. Here is example of my fucntion:
function getData(fnName,storageID,recID){
var inStorage = localStorage.hasOwnProperty(storageID) ? true : false,
frmData;
if(inStorage) {
frmData = JSON.parse(localStorage.getItem(storageID));
}else{
$.ajax({
type: 'POST',
url: 'AjaxFunctions.cfc?method='+fnName,
data: {'recID':recID},
dataType: 'json',
async: false
}).done(function(obj){
if(obj.STATUS == "200"){
var storageData = $.isEmptyObject(obj.DATA) ? null : JSON.stringify(obj.DATA);
localStorage.setItem(storageID,storageData);
frmData = storageData;
}else{
$('#error').html(obj.MESSAGE);
}
}).fail(function(jqXHR, textStatus, errorThrown){
alert("Error: "+errorThrown);
});
}
//frmFeed(frmData);
return frmData;
}
Function above once completed should pass the data in another function that will populate the form:
function frmFeed(frmData){
//Loop over frmData and populate the fields
}
I know the one way to accomplish this is to simply call frmFeed inside getData function that I showed above (commented code). is there any other way to call frmFeed and pass the data? If anyone can provide some example please let me know. Thank you!
There are several ways:
Callbacks
Promises
Not recommended would be to use synchronous ajax requests because it will block the UI.
Here's an implementation using promises:
function getData(fnName,storageID,recID){
return new Promise(function(resolve, reject) {
var inStorage = localStorage.hasOwnProperty(storageID) ? true : false;
if (inStorage) {
resolve(JSON.parse(localStorage.getItem(storageID)));
} else {
$.ajax({
type: 'POST',
url: 'AjaxFunctions.cfc?method='+fnName,
data: { 'recID': recID },
dataType: 'json'
// removed sync
}).done(function(obj){
if(obj.STATUS == "200"){
var storageData = $.isEmptyObject(obj.DATA) ? null : JSON.stringify(obj.DATA);
localStorage.setItem(storageID,storageData);
resolve(storageData);
}else{
$('#error').html(obj.MESSAGE);
// or reject here
reject(obj);
}
}).fail(function(jqXHR, textStatus, errorThrown){
alert("Error: "+errorThrown);
// or reject may be better here
reject({ 'jqXHR': jqXHR, 'textStatus': textSTatus, 'errorThrown': errorThrown });
});
}
});
}
getData('blah', 'storageId', 'recId')
.then(function(frmData) {
frmFeed(frmData);
});

Parse XML catch block not catching exception in JS

I have a function that takes an XML file (obtained via AJAX) as input, parses it as XML and then execute some functions on it. A stripped down version can be found below.
AJAX
$.ajax({
type: "GET",
url: "./default.xml",
dataType: "xml",
success: function(data) {
parseMech(data);
}
});
parseMech function
function parseMech(xml) {
try {
var xmlObject = $(xml);
// See the output function below
$(".tree.base").html(treeBuilder(xmlObject.find("node").first()));
console.log("succes?");
} catch(e) {
$("#error-msg > .the-msg").text(" Invalid XML structure").parent().fadeIn(250);
console.log("Failed");
}
}
treeBuilder function
function treeBuilder(nodes) {
var newList = $("<ol>");
nodes.each(function (x, e) {
var newItem = $('<li> </li>');
for (var i = 0, l = e.attributes.length, a = null; i < l; i++) {
// Don't forget to add properties as data-attributes
a = e.attributes[i];
newItem.attr("data-" + a.nodeName, a.value);
if (a.nodeName == "cat" || a.nodeName == "word") {
newItem.html('' + a.value + '');
}
}
if ($(this).children('node').length) {
newItem.append(output($(this).children('node')));
}
newList.append(newItem);
});
return newList;
}
This works as it should when default.xml is a valid xml file. However, when it's not (for instance when I leave out a closing tag) the catch blok is not executed. In other words: when executing all functions with an invalid XML as source, neither console logs are executed, even though you would expect at least one (in try or in catch) to be logged.
Am I missing something here?
You need a fail handler in your ajax call.
According to the docs, a jquery ajax call with a dataType of xml returns a xml doc, so the data stream is being parsed in the course of the ajax call.
Alter the ajax call as follows (behaviour verified):
//...
error: function() {
console.log("ajax failed!");
},
//...
Note
Consider to change the way you specify your handlers,as error and success attributes are deprecated:
top.$.ajax({
type: "GET",
url: url,
crossDomain: true,
dataType: "xml",
})
.fail ( function() {
console.log("ajax failed!");
})
.done ( function(data) {
console.log("ajax ok!");
parseMech(data);
});

Callback with javascript and jquery

I am more of a java developer and am having difficulty with javascript callback. I am wondering if any experts here would help me out of my struggle with this code.
I am trying to pull our locations from db and populating in an array. On first load i am trying to refresh all locations and I am having trouble to control the flow of execution and loading values. Below is the code and I have put in the output at the end.
JQUERY CODE:
// load all locations on first load.
refreshLocations();
$("#locInput").autocomplete({source: locationData});
}); // end of document.ready
// function to refresh all locations.
function refreshLocations() {
getLocationArray(function(){
console.log("firing after getting location array");
});
}
// function to get the required array of locations.
function getLocationArray() {
getJsonValues("GET", "getLocalityData.php", "", getLocalityFromJson);
}
// function to pick up localities from json.
function getLocalityFromJson(json){
if (!json) {
console.log("====> JSON IS NOT DEFINED !! <====");
return;
} else {
console.log("json is defined so processing...");
var i = 0;
$.each(json.listinginfo, function() {
var loc = json.listinginfo[i].locality;
locationArray[i] = loc;
console.log("added location ->" + locationArray[i]);
i++;
});
}
//return locationArray;
}
// function to get raw json from db.
function getJsonValues(type, url, query, getLocalityFromJson) {
var json;
// if the previous request is still pending abort.
if (req !== null)
req.abort();
var searchString = "";
if (query !== "") {
searchString = "searchStr" + query;
}
console.log("searchString : (" + query + ")");
req = $.ajax({
type: type,
url: url,
data: searchString,
contentType: "application/json; charset=utf-8",
dataType: "text",
success: function(result) {
json = JSON.parse(result);
console.log("========start of json
return============");
console.log(JSON.stringify(json));
console.log("========end of json
return============");
//return json;
}
});
getLocalityFromJson(json);
return json;
}
the output from above code is as follows:
searchString : () (18:25:36:473)
at locality1.php:74
====> JSON IS NOT DEFINED !! <==== (18:25:36:518)
at locality1.php:48
========start of json return============ (18:25:37:606)
at locality1.php:83
{"listinginfo":[{"listing":"1","locality":"birmingham"},
{"listing":"2","locality":"oxford"}]} (18:25:37:624)
at locality1.php:84
========end of json return============ (18:25:37:642)
at locality1.php:85
>
Help will be greatly appreciated.
call getLocalityFromJson(json); inside your success callback
function getJsonValues(type, url, query, getLocalityFromJson) {
var json;
// if the previous request is still pending abort.
if (req !== null)
req.abort();
var searchString = "";
if (query !== "") {
searchString = "searchStr" + query;
}
console.log("searchString : (" + query + ")");
req = $.ajax({
type: type,
url: url,
data: searchString,
contentType: "application/json; charset=utf-8",
dataType: "text",
success: function(result) {
json = JSON.parse(result);
console.log("========start of json return============");
console.log(JSON.stringify(json));
console.log("========end of json return============");
//return json;
getLocalityFromJson(json);
}
});
}
You need to call getLocalityFromJson(json) and return json inside your ajax success function. Ajax requests are asynchronous, there's no guarantee that the request will be finished by the time you get to the lines getLocalityFromJson(json); return(json); where they are currently.
The call back functions from a jquery ajax call is complete, failure, success, etc..
Success is called after a request is successful,
Failure is called if theres something like an error 500, or a 404, or w/e.
Complete is Always called after a ajax call.
If you want your code to just follow sequence like in java, throw async: false into your ajax call.. but I wouldnt' recommend this as it defeats the purpose of using this method, and also locks up your browser.
You should make sure you are waiting for the request to finish before moving on - so put code in the success function that you want to run AFTER the request has finished fetching your data.
I think you need to remember Ajax is running async, so you need to follow this thread to execute your refresh.

Getting typeError:e is undefined in firebug while running a script

I am not able to figure out what is wrong with my code.I am getting data from post as an array and I am then displaying that data in box.
function worker() {
var a = $("#BeeperBox");
var delay =2000;
$.ajax({
url: '/index.php/admin/getLatest',
success: function(data) {
$.each(data.upda,function(i, v){
var out = v.name + v.mob ;
$('span.blueName').html(out);
$("#BeeperBox").show();
timerId = setTimeout(function () {
a.hide();
}, delay);
});
},
complete: function() {
// Schedule the next request when the current one's complete
setTimeout(worker, 50000);
}
});
}
When i run it firebug shows error: TypeError: e is undefined.
since your sending the response as JSON.. its better to specify your dataType as JSON (though If none is specified, jQuery will try to infer it based on the MIME type of the response ) so that you don't have to parse it manaully..i think the problem here is you havn't parsed the json that you got as response
try this
$.ajax({
url: '/index.php/admin/getLatest',
dataType: 'json',
success: function(data) {
$.each(data.upda,function(i, v){
var out = v.name + v.mob ;
......
},
Check if data.upda is undefined, I think the problem is that that variable doesn't exist and you're trying to iterate over a undefined element.

Save temporary Ajax parameters in jQuery

I am developing a heavily scripted Web application and am now doing some Error handling. But to do that, I need a way to access the AJAX parameters that were given to jQuery for that specific AJAX Request. I haven't found anything on it at jquery.com so I am asking you folks if you have any idea how to accomplish that.
Here is an example of how I want to do that codewise:
function add_recording(filename) {
updateCounter('addRecording','up');
jQuery.ajax({
url: '/cgi-bin/apps/ajax/Storyboard',
type: 'POST',
dataType: 'json',
data: {
sid: sid,
story: story,
screen_id: screen_id,
mode: 'add_record',
file_name: filename
},
success: function(json) {
updateCounter('addRecording','down');
id = json[0].id;
create_record(id, 1, 1, json);
},
error: function() {
updateCounter('addRecording','error',hereBeData);
}
})
}
hereBeData would be the needed data (like the url, type, dataType and the actual data).
updateCounter is a function which updates the Status Area with new info. It's also the area where the User is notified of an Error and where a Dismiss and Retry Button would be generated, based on the Info that was gathered in hereBeData.
Regardless of calling complete() success() or error() - this will equal the object passed to $.ajax() although the values for URL and data will not always be exactly the same - it will convert paramerters and edit the object around a bit. You can add a custom key to the object to remember your stuff though:
$.ajax({
url: '/',
data: {test:'test'},
// we make a little 'extra copy' here in case we need it later in an event
remember: {url:'/', data:{test:'test'}},
error: function() {
alert(this.remember.data.test + ': error');
},
success: function() {
alert(this.remember.data.test + ': success');
},
complete: function() {
alert(this.remember.data.url + ': complete');
}
});
Of course - since you are setting this data originally from some source - you could rely on the variable scoping to keep it around for you:
$("someelement").click(function() {
var theURL = $(this).attr('href');
var theData = { text: $(this).text(); }
$.ajax({
url: theUrl,
data: theData,
error: function() {
alert('There was an error loading '+theURL);
}
});
// but look out for situations like this:
theURL = 'something else';
});
Check out what parameters you can get in the callback for error.
function (XMLHttpRequest, textStatus, errorThrown) {
// typically only one of textStatus or errorThrown
// will have info
this; // the options for this ajax request
}
You can use the ajax complete event which passes you the ajaxOptions that were used for the request. The complete fires for both a successful and failed request.
complete : function (event, XMLHttpRequest, ajaxOptions) {
//store ajaxOptions here
//1 way is to use the .data on the body for example
$('body').data('myLastAjaxRequest', ajaxOptions);
}
You can then retireve the options using
var ajaxOptions = $('body').data('myLastAjaxRequest');

Categories