This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
How can I access the value of a promise?
(14 answers)
How do I promisify native XHR?
(6 answers)
Closed 9 days ago.
I am trying to extract value from a Promise. I am able to print the result before it gets returned in a Promise.
function countTotalInvItem() {
var params = 'service=shopping&request=getshopitems&mode=count';
var jsonRes = xmlHttpSend(params).then((value) => {
if (value instanceof Promise) {
console.log('Promise found');
} else {
console.log('Promise NOT');
if (value != null) {
console.log('Value: ' + value);
} else {
console.log('NULL value');
}
}
});
}
async function xmlHttpSend(params) {
let myPromise = new Promise(function (resolve) {
var xhr = new XMLHttpRequest();
var url = 'portal?' + params;
xhr.onreadystatechange = function (response) {
if (xhr.readyState == 4 && xhr.status == 200) {
var rs = parseReturn(xhr.responseText);
console.log('ResultSet >>> ' + rs.toString());
if (
rs.success === 'true' &&
rs.resultPayloadType === 'json' &&
rs.result !== null
) {
console.log('Parsing JSON ...');
var json = JSON.parse(rs.result);
if (json === null) {
console.log('NO JSON RESULT !!!');
} else {
console.log('JSON Result Parsed: ' + json[0].count);
}
resolve(json);
} else {
console.log('RS has ERROR !!!');
resolve(null);
}
}
};
xhr.open('GET', url, true);
xhr.send();
});
}
function parseReturn(input) {
var kvArrays1 = input.split('&');
var service = null;
var sessionID = null;
var success = false;
var errorCode = -1;
var resultEncoding = null;
var resultPayloadType = null;
var result = null;
if (kvArrays1.length > 0) {
for (let i = 0; i < kvArrays1.length; i++) {
if (kvArrays1[i] != null) {
var kvArrays2 = kvArrays1[i].split('=');
if (kvArrays2 != null) {
switch (kvArrays2[0]) {
case 'service':
if (kvArrays2.length == 2) {
service = kvArrays2[1];
}
break;
case 'sessionID':
if (kvArrays2.length == 2) {
sessionID = kvArrays2[1];
}
break;
case 'success':
if (kvArrays2.length == 2) {
success = kvArrays2[1];
}
break;
case 'errorCode':
if (kvArrays2.length == 2) {
errorCode = kvArrays2[1];
}
break;
case 'resultEncoding':
if (kvArrays2.length == 2) {
resultEncoding = kvArrays2[1];
}
break;
case 'resultPayloadType':
if (kvArrays2.length == 2) {
resultPayloadType = kvArrays2[1];
}
break;
case 'result':
if (kvArrays2.length >= 2) {
result = '';
for (let j = 1; j < kvArrays2.length; j++) {
if (kvArrays2[j] == '') {
result += '=';
} else {
result = kvArrays2[j];
}
}
}
break;
}
}
}
}
}
return new ResultSet(
service,
sessionID,
success,
errorCode,
resultEncoding,
resultPayloadType,
result
);
}
class ResultSet {
constructor(
service,
sessionID,
success,
errorCode,
resultEncoding,
resultPayloadType,
result
) {
this.service = service;
this.sessionID = sessionID;
this.success = success;
this.errorCode = errorCode;
this.resultEncoding = resultEncoding;
this.resultPayloadType = resultPayloadType;
if (result != null) {
if (result.length > 0) {
this.result = atob(result);
}
}
}
toString() {
return (
'service: ' +
this.service +
'; sessionID: ' +
this.sessionID +
'; success: ' +
this.success +
'; errorCode: ' +
this.errorCode +
'; resultEncoding: ' +
this.resultEncoding +
'; resultPayloadType: ' +
this.resultPayloadType +
'; result: ' +
this.result
);
}
}
<!DOCTYPE html>
<html>
<head>
<script>
</script>
</head>
<body>
<div id="demo">
<h2>Count Total Inventory Items</h2>
<button type="button" onclick="countTotalInvItem()">Count</button>
</div>
</body>
</html>
The output as the screenshot shows with the developer console opened.
I am able to receive the response and to print out the 'count' number from the JSON that is returned.
I am missing something to pass the JSON from 'xmlHttpSend' async function to the 'countTotalInvItem' and print it as a value (which should be value of '1') ?
Thanks.
I can't get that code to run properly to try to edit it, but your function xmlHttpSend does not return anything.
It declares a variable (myPromise) but does not use it. If you want this function to return a promise, you can just do:
return new Promise(function (resolve) {
instead of
let myPromise = new Promise(function (resolve) {
It is not necessary to declare xmlHttpSend as async since it returns a promise, the purpose of async is to avoid writing promises explicitly. You should also avoid using var as much as possible, it makes your code harder to understand because of the scope it gives to the variable.
It is the same thing for the != and == in your functions, you should try to use !== and === as much as possible as it is easier to understand and to debug
Related
We've just started using the bot-framework. For client side we are using the cdn and not react. We have certain links that bot responds with. And we would like to append a url parameter to each link and open the link in the same window. So far this is what my code looks like. Is there a better way to achieve this using the botframework. I know there is cardActionMiddleware which has openUrl cardAction, but we don't have any cards and I am not sure on how to implement that.
var webchatMount = document.getElementById('webchatMount');
function loadChatbot() {
var xhr = new XMLHttpRequest();
xhr.open('GET', "https://webchat.botframework.com/api/tokens", true);
xhr.setRequestHeader('Authorization', 'BotConnector ' + '<secret>');
xhr.send();
xhr.onreadystatechange = function (e) {
if (xhr.readyState == 4 && xhr.status == 200) {
var response = JSON.parse(xhr.responseText);
var store = window.WebChat.createStore({}, function ({ dispatch }) {
return function (next) {
return function (action) {
if (action.type === 'DIRECT_LINE/INCOMING_ACTIVITY') {
var event = new Event('webchatincomingactivity');
event.data = action.payload.activity;
window.dispatchEvent(event);
}
return next(action);
}
}
});
window.WebChat.renderWebChat(
{
directLine: window.WebChat.createDirectLine({ token: response }),
store: store,
},
webchatMount
);
document.querySelector('.webchat__send-box-text-box__input').focus();
window.addEventListener('webchatincomingactivity', ({ data }) => {
setTimeout(function () {
var links = document.querySelectorAll('#webchatMount a');
if (links.length >= 1) {
for (var i = 0; i <= links.length; i++) {
if (links[i] == undefined)
break;
var compare = new RegExp('maindomain');
var href = links[i].getAttribute('href');
var st = getParameterByName('st', href);
if (links[i].hasAttribute('target')) {
links[i].removeAttribute('target');
}
if (compare.test(href)) {
// internal link
// check if it has st=INTRA
if (st) {
console.log(' it has a value');
} else {
links[i].setAttribute('href', insertParam('st', 'INTRA', href));
}
} else {
// external link, do nothing
}
}
}
}, 1000);
});
}
}
}
and here are getParameterByName and insertParam functions.
function getParameterByName(name, url) {
name = name.replace(/[\[\]]/g, '\\$&');
var regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)'),
results = regex.exec(url);
if (!results) return null;
if (!results[2]) return '';
return decodeURIComponent(results[2].replace(/\+/g, ' '));
}
function insertParam(key, value, url) {
key = encodeURIComponent(key);
value = encodeURIComponent(value);
// kvp looks like ['key1=value1', 'key2=value2', ...]
var kvp = url.split('&');
var i=0;
for(; i<kvp.length; i++){
if (kvp[i].startsWith(key + '=')) {
var pair = kvp[i].split('=');
pair[1] = value;
kvp[i] = pair.join('=');
break;
}
}
if(i >= kvp.length){
kvp[kvp.length] = [key,value].join('=');
}
return kvp.join('&');
}
I am new to botframework webchat so I don't know it very well. I know that the secret should not be used like that, but for know we are testing and would like to get it to work. Any help would be appericiated
Thanks.
Json request being sent to backend throws the exception. Where is my mistake?
Could not write JSON: EL1025E: The collection has '0' elements, index '0' is invalid; nested exception is com.fasterxml.jackson.databind.JsonMappingException: EL1025E: The collection has '0' elements, index '0' is invalid (through reference chain: org.springframework.data.domain.PageImpl["content"]->java.util.Collections$UnmodifiableRandomAccessList[3]->com.sun.proxy.$Proxy277["teacherName"])
The server encountered an unexpected condition that prevented it from fulfilling the request.
Java code
public Page<CourseProjection> fetchAllPublishCourses(Integer page, Integer size, String search,
String sortBy) {
Page<CourseProjection> response = null;
JsonParser jsonParser = new JsonParser();
Specification<Course> spec = null;
LinkedList<Filter> subjectFilters = new LinkedList<>();
LinkedList<Filter> subCategoryFilters = new LinkedList<>();
LinkedList<Filter> examSegmentFilters = new LinkedList<>();
LinkedList<Filter> categoryFilters = new LinkedList<>();
LinkedList<Filter> otherFilters = new LinkedList<>();
try {
Pageable pageable = null;
Sort sort = null;
if (search != null && !search.isEmpty()) {
JsonObject jsonObject = (JsonObject) jsonParser.parse(search);
if (jsonObject != null) {
JsonArray jsonArray = (JsonArray) jsonObject.get("filters");
for (int i = 0; i < jsonArray.size(); i++) {
Filter filter = new Filter();
filter.setFilterName(
((JsonObject) jsonArray.get(i)).get("filterName").toString().replaceAll("\"", ""));
filter.setValue(
((JsonObject) jsonArray.get(i)).get("value").toString().replaceAll("\"", ""));
if (filter.getFilterName().equalsIgnoreCase("courseSubject")) {
subjectFilters.add(filter);
} else if (filter.getFilterName().equalsIgnoreCase("courseSubCategory")) {
subCategoryFilters.add(filter);
} else if (filter.getFilterName().equalsIgnoreCase("courseExamSegment")) {
examSegmentFilters.add(filter);
} else if (filter.getFilterName().equalsIgnoreCase("courseCategory")) {
if (filter.getValue().equalsIgnoreCase("current affairs")) {
Filter currentAffairsFilter = new Filter();
currentAffairsFilter.setFilterName("courseSubject");
currentAffairsFilter.setValue("Current Affairs");
subjectFilters.add(currentAffairsFilter);
} else {
categoryFilters.add(filter);
}
} else {
otherFilters.add(filter);
}
}
otherFilters.add(Filter.addDeafultFilter());
}
if (otherFilters != null && otherFilters.size() > 0) {
CourseSpecificationBuilder builder = new CourseSpecificationBuilder();
spec = builder.build(otherFilters, subjectFilters, subCategoryFilters, examSegmentFilters,
categoryFilters);
}
}
if (sortBy != null && !sortBy.isEmpty()) {
switch (sortBy) {
case "atoz":
sort = new Sort(Direction.ASC, new String[]{"courseTitle"});
break;
case "ztoa":
sort = new Sort(Direction.DESC, new String[]{"courseTitle"});
break;
case "popular":
sort = new Sort(Direction.ASC, "position");
break;
}
}
if (spec != null) {
if (page != null && size != null) {
if (sort != null) {
pageable = PageRequest.of(page, size, sort);
response = courseRepository.findAll(spec, CourseProjection.class, pageable);
} else {
pageable = PageRequest.of(page, size);
response = courseRepository.findAll(spec, CourseProjection.class, pageable);
}
} else {
pageable = PageRequest.of((page != null ? page : 0), (size != null ? size : 0));
response = courseRepository.findAll(spec, CourseProjection.class, pageable);
}
}
} catch (Exception e) {
LOGGER.error(Course.class.getName() + " Exception Occurred");
emailService.sendErrorLogsToDevelopers(ExceptionUtils.getStackTrace(e));
}
return response;
}
JavaScript
var obj2 = JSON.stringify(obj);
$.ajax({
url: apiBasePath + '/courses?page=' + page_num + '&size=12&sort='
+ sortCourses + '&search='
+ encodeURIComponent(JSON.stringify(obj)),
type: "GET",
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function (response) {
console.log("Success : " + response);
$('.load-courses-progress-bar').hide();
$('.course-listing').css("visibility", "visible");
$('.mat-content').css("overflow-y", "auto")
if ($(window).width() > '767') {
$('body,html').animate({
scrollTop: $(".course-listing").offset().top - 100
}, 1000);
setTimeout(function () {
$('.mat-all-curses-main-tab').hide();
}, 2000);
} else {
$(".mat-all-curses-main-tab-mobile").hide("0", function () {
$('body,html').animate({
scrollTop: $(".course-listing").offset().top - 200
}, 1000);
})
}
showCourses(response);
showTrendingCourse(response, obj);
},
error: function (response) {
console.log("Error : " + JSON.stringify(response));
}
});
What I am trying to do is run functions that will send out messages. The problem with node js is that it does not return in sequence. I do however want each function to run in the sequence that it is coded.
Not really sure what I'm missing here.
Right now I can get it to return only message 1 and message 2 in sequence BUT I want to go all the way from callfirstmessage to callfifthmessage. When I have tried to do this they all get returned out of order.
var promise = new Promises(function(resolve, reject) {
// do some async stuff
callfirstmessage();
//resolve(data);
if (success) {
resolve(data);
} else {
reject(reason);
}
});
promise.then(function(data) {
// function called when first promise returned
return new Promises(function(resolve, reject) {
// second async stuff
callthirdmessage();
//resolve(data);
if (success) {
resolve(data);
} else {
reject(reason);
}
});
}, function(reason) {
// error handler
}).then(function(data) {
callsecondmessage();
}, function(reason) {
// second error handler
});
I have looked at a few different posts talking about this topic and I have used those suggestions. I think my issue here is not being able to successfully chain these together. I have spent a few days on this with no additional progress...I need help bad!
-----------------------edit----------------------------
I think I need to apply something similar to this .then I have found here: https://coderwall.com/p/ijy61g/promise-chains-with-node-js. But for some reason it is still sending messages at random.
Maybe, I'm just going in the completely wrong direction. :/
Below is everything I am working with
// dependencies
console.log("starting program");
var async = require('async');
var AWS = require('aws-sdk');
var Converter = require("csvtojson").Converter;
var util = require('util');
var Promises = require('pinkie-promise');
var vow = require('vow');
var s3 = new AWS.S3();
var snsTopicEMAIL = new AWS.SNS({
params: {
TopicArn: 'arn:aws:sns:xxxxxxxxxxxxxxxxxxxxxxxx'
}
});
var snsTopicSMS = new AWS.SNS({
params: {
TopicArn: 'arn:aws:sns:xxxxxxxxxxxxxxxxxxxxxxxxx'
}
});
var abort = false;
//SMS
function topDSRsms(csvJSON) {
var ytdTopReg = "";
if (csvJSON.length < 1) {
console.error("Not enough data records in CSV to compose an SMS. Aborting. count:" + csvJSON.length);
tdTopReg = "There was an error. Please contact IT for assistance.";
abort = true;
throw '';
}
ytdTopReg = "";
for (var i = 0; i < csvJSON.length; i++) {
var csvItem = csvJSON;
if (csvItem[i].KPIvalue.length > 0 && csvItem[i].KPI.length > 0) {
var KPI = " " + csvItem[i].KPI + ":" + csvItem[i].KPIvalue + "\n";
} else {
KPI = " ";
}
if (csvItem[i].TrendValue1.length > 0 && csvItem[i].Trend1.length > 0) {
var trend1 = "\n" + svItem[i].Trend1 + ":" + csvItem[i].csvItem[i].TrendValue1;
} else {
trend1 = "";
}
if (csvItem[i].TrendValue2.length > 0 && csvItem[i].Trend2.length > 0) {
var trend2 = "\n" + csvItem[i].Trend2 + ":" + csvItem[i].TrendValue2;
} else {
trend2 = "";
}
if (csvItem[i].TrendValue3.length > 0 && csvItem[i].Trend3.length > 0) {
var trend3 = "\n" + csvItem[i].Trend3 + ":" + csvItem[i].TrendValue3;
} else {
trend3 = "";
}
ytdTopReg += "\n#" + (i + 1) + KPI + csvItem[i].RankTrend + ":" + csvItem[i].RankTrendValue + trend1 + trend2 + trend3;
}
return ytdTopReg;
}
function dshSmsStr(csvJSON) {
return "DSR:" +
topDSRsms(csvJSON);
}
//email
function topDSREmail(csvJSON) {
var ytdTopReg = "";
ytdTopReg = "Top orders By Region - ";
for (var i = 0; i < csvJSON.length; i++) {
if (csvJSON.length < 1) {
console.error("Not enough data records in CSV to compose an email. Aborting.");
ytdTopReg = "There was an error. Please contact IT for assistance."
abort = true;
throw '';
//return -1;
} else {
var csvItem = csvJSON;
if (csvItem[i].KPIvalue.length > 0 && csvItem[i].KPI.length > 0) {
var KPI = " " + csvItem[i].KPI + ":" + csvItem[i].KPIvalue + "\n";
} else {
KPI = "";
}
if (csvItem[i].TrendValue1.length > 0 && csvItem[i].Trend1.length > 0) {
var trend1 = "\n" + svItem[i].Trend1 + ":" + csvItem[i].csvItem[i].TrendValue1;
} else {
trend1 = "";
}
if (csvItem[i].TrendValue2.length > 0 && csvItem[i].Trend2.length > 0) {
var trend2 = "\n" + csvItem[i].Trend2 + ":" + csvItem[i].TrendValue2;
} else {
trend2 = "";
}
if (csvItem[i].TrendValue3.length > 0 && csvItem[i].Trend3.length > 0) {
var trend3 = "\n" + csvItem[i].Trend3 + ":" + csvItem[i].TrendValue3;
} else {
trend3 = "";
}
ytdTopReg += "\n#" + (i + 1) + KPI + csvItem[i].RankTrend + ":" + csvItem[i].RankTrendValue + trend1 + trend2 + trend3 + "\n";
}
}
return ytdTopReg;
}
function dshEmailStr(csvJSON) {
return "DSR:" +
topDSREmail(csvJSON);
}
console.log("compiled totals string and customer string");
exports.handler = function(event, context) {
// Read options from the event.
console.log("Reading options from event:\n", util.inspect(event, {
depth: 5
}));
var srcBucket = event.Records[0].s3.bucket.name;
console.log("got src bucket name");
// Object key may have spaces or unicode non-ASCII characters.
var srcKey = decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, " "));
console.log("src key decoded");
// Download the CSV file from S3, Extract&Load data into DynamoDB, and notify end users.
async.waterfall([
function downloadCSV(next) {
// Download the Daily Sales Highlights CSV file from S3 into a buffer.
s3.getObject({
Bucket: srcBucket,
Key: srcKey
},
next);
},
function parseCSV(response, next) {
console.log(response.ContentType);
var csvStream = AWS.util.buffer.toStream(response.Body);
var csvJSON = [];
var converter = new Converter({});
//end_parsed will be emitted once parsing finished
converter.on("end_parsed", function(jsonArray) {
console.log(jsonArray); //here is your result jsonarray
csvJSON = jsonArray;
next(null, csvJSON);
});
//read CSV from stream
csvStream.pipe(converter);
},
function updateState(csvJSON, next) {
//Update state in DynamoDB
next(null, csvJSON);
},
function notifyEndUsers(csvJSON, next) {
//Notify end users
console.log("\n\nNotifying SMS end users...\n\n");
console.log(dshSmsStr(csvJSON));
console.log("\n\nNotifying email end users...\n\n");
console.log(dshEmailStr(csvJSON));
//email
snsTopicEMAIL.publish({
Message: dshEmailStr(csvJSON)
}, function(err, data) {
if (err) {
console.log(err.stack);
next(err);
}
console.log(data);
next(null);
});
//SMS
var datastr = dshSmsStr(csvJSON);
var strlen = dshSmsStr(csvJSON).length;
var ranscript = false;
var completemsg1 = false;
var completemsg2 = false;
var completemsg3 = false;
var completemsg4 = false;
var completemsg5 = false;
var completemsg6 = false;
function callfirstmessage() {
snsTopicSMS.publish({
Message: dshSmsStr(csvJSON).substring(0, 150)
}, function(err, data) {
if (err) {
console.log(err.stack);
next(err);
}
console.log(data);
next(null);
});
return true;
}
function callsecondmessage() {
snsTopicSMS.publish({
Message: dshSmsStr(csvJSON).substring(150, 300)
}, function(err, data) {
if (err) {
console.log(err.stack);
next(err);
}
console.log(data);
next(null);
});
return true;
}
function callthirdmessage() {
snsTopicSMS.publish({
Message: dshSmsStr(csvJSON).substring(300, 450)
}, function(err, data) {
if (err) {
console.log(err.stack);
next(err);
}
console.log(data);
next(null);
});
return true;
}
function callfourthmessage() {
snsTopicSMS.publish({
Message: dshSmsStr(csvJSON).substring(450, 600)
}, function(err, data) {
if (err) {
console.log(err.stack);
next(err);
}
console.log(data);
next(null);
});
return true;
}
function callfifthmessage() {
snsTopicSMS.publish({
Message: dshSmsStr(csvJSON).substring(600, 750)
}, function(err, data) {
if (err) {
console.log(err.stack);
next(err);
}
console.log(data);
next(null);
});
return true;
}
function one() {
new Promises(function(resolve1, reject) {
completemsg1 = callfirstmessage();
if (completemsg1 === true) {
resolve1(true);
console.log('first success');
} else {
reject(false);
console.log('first fail');
}
});
}
function two() {
new Promises(function(resolve2, reject) {
completemsg2 = callsecondmessage();
if (completemsg2 === true) {
resolve2(completemsg2);
console.log('second success');
} else {
reject(false);
console.log('second fail');
}
});
}
function three() {
new Promises(function(resolve3, reject) {
completemsg3 = callthirdmessage();
if (completemsg3 === true) {
resolve3(completemsg3);
console.log('third success');
} else {
reject(false);
console.log('third fail');
}
});
}
function four() {
new Promises(function(resolve4, reject) {
completemsg4 = callfourthmessage();
if (completemsg4 === true) {
resolve4(completemsg4);
console.log('fourth success');
} else {
reject(false);
console.log('fourth fail');
}
});
}
function five() {
new Promises(function(resolve5, reject) {
completemsg5 = callfifthmessage();
if (completemsg5 === true) {
resolve5(completemsg5);
console.log('fifth success');
} else {
reject(false);
console.log('fifth fail');
}
});
}
console.log("\n\n Begin SMS script. Data length :" + strlen + "...\n\n");
if (strlen < 150) { //one message sent
//Will complete later
ranscript = true;
} else if (strlen < 300) { //two messages sent
//Will complete later
ranscript = true;
} else if (strlen < 450) { //three messages sent
//Will complete later
ranscript = true;
} else if (strlen < 600) { //four messages sent
one().then(function() {
return two();
})
.then(function() {
return three();
})
.then(function() {
return four();
})
.then(function() {
return five();
});
ranscript = true;
} else if (strlen < 750) { //five messages sent
//Will complete later
ranscript = true;
} else {
console.log("\n\n The SMS mesages is too large to send to end users...\n\n");
}
if (ranscript === false) {
console.log("\n\n SMS script did not run \n\n");
} else if (ranscript === true) {
console.log("\n\n SMS script successfully ran \n\n");
}
}
], function(err) {
if (err) {
console.error(
'Unable to process due to an error: ' + err
);
} else {
console.log(
'Successfully processed'
);
}
context.done();
});
}
The executor for the first promise (reformatted):
var promise = new Promise(function(resolve, reject)
{ // do some async stuff
callfirstmessage();
if (success)
{ resolve(data);
} else
{ reject(reason);
}
});
doesn't resolve or reject the returned promise asynchronously. You will need to get a call back from the asynchronous operation before resolving/rejecting the returned promise. In pseudo code something more like:
var promise = new Promise(function(resolve, reject)
{ // do some async stuff
callfirstmessage( successCallBack, failCallBack);
function successCallBack( data)
{ resolve(data);
}
function failCallBack( reason)
{ reject(reason);
}
});
In reality you may have to use a call back the asynchronous operation supports, and then analyze success or failure of the operation depending on a status property located in a request or response object.
I'm trying to execute several pl/sql blocks in a Dynamic Action, with feedback to the end user with a modal dialog reporting the current satus.
Something like:
Processing Step 1...
/*Run pl/sql code for step 1*/
Processing Step 2...
/*Run pl/sql code for Step 2*/
and so on...
Both, the pl/sql and javascript code, run as intended but when I combined them on a Dynamic Action in the sequence:
1 - Execute Javascript
2 - Execute PL/SQL block /* With wait for result option checked*/
3 - Execute Javascript
4 - Execute PL/SQL block
The status dialog is not been shown, however the pl/sql blocks are completed without problems.
I realize that this must be something related to javascript not been multithreaded, so I've moved the pl/sql block to application processes and run them as ajax calls like this:
function something(){
var get;
var result = 0;
updateStatus('Running Step1');
get = new htmldb_Get(null,$v('pFlowId'),'APPLICATION_PROCESS=P6_STEP_1',0);
result = get.get();
if(result > 0){
updateStatus('Running Step 2');
get = new htmldb_Get(null,$v('pFlowId'),'APPLICATION_PROCESS=P6_STEP_2',0);
result = get.get();
}
closeStatusDialog();
}
But still, as before, the processes run fine but the dialog doesn't appear. Finally I added a setTimeOut function to each call, like this:
function something(){
var get;
var result = 0;
updateStatus('Running Step1');
get = new htmldb_Get(null,$v('pFlowId'),'APPLICATION_PROCESS=P6_STEP_1',0);
result = setTimeOut(get.get(),500);
if(result > 0){
updateStatus('Running Step 2');
get = new htmldb_Get(null,$v('pFlowId'),'APPLICATION_PROCESS=P6_STEP_2',0);
result = setTimeOut(get.get(),500);
}
closeStatusDialog();
}
But still nothing. What can I do to get this running as needed?.
I've checked the browser console and no exeptions are been thrown, likewise with the pl/sql blocks.
I've solved it, although the solution doesn't rely on dynamic actions, just javascript and applicacion processes. I'm posting this for anyone with a similar problem.
The htmldb_Get Javascript object is an oracle-apex wrapper for the XMLHttpRequest AJAX object. Poorly documented though.
I've found a copy of the code (at the bottom) and it turns out it has another function called GetAsync that allows to pass a function as a parameter to asign it to the onreadystatechange attribute on the XMLHttpRequest object, which will be executed each time the attribute readyState of the underlying XMLHttpRequest changes.
The function passed as a parameter can't have parameters on its own definition.
So, instead of calling get() on the htmldb_Get object you need to call GetAsync(someFunction)
With this solution in my case:
function something(){
var get;
get = new htmldb_Get(null,$v('pFlowId'),'APPLICATION_PROCESS=P6_STEP_1',0);
get.GetAsync(someFunctionStep1);
}
function someFunctionStep1(){
if(p.readyState == 0){ /*p is the underlying XMLHttpRequest object*/
console.log("request not initialized");
updateStatus('Running Step 1');
} else if(p.readyState == 1){
console.log("server connection established");
} else if(p.readyState == 2){
console.log("request received");
} else if(p.readyState == 3){
console.log("processing request");
} else if(p.readyState == 4){
console.log("request finished and response is ready");
callStep2();
}
}
function callStep2(){
var get;
get = new htmldb_Get(null,$v('pFlowId'),'APPLICATION_PROCESS=P6_STEP_2',0);
get.GetAsync(someFunctionStep2);
}
function someFunctionStep2(){
if(p.readyState == 0){
console.log("request not initialized");
updateStatus('Running Step 2');
} else if(p.readyState == 1){
console.log("server connection established");
} else if(p.readyState == 2){
console.log("request received");
} else if(p.readyState == 3){
console.log("processing request");
} else if(p.readyState == 4){
console.log("request finished and response is ready");
closeDialog();
}
}
Here's the htmldb_get definition, at the end is the GetAsync function
/*
str should be in the form of a valid f?p= syntax
*/
function htmldb_Get(obj,flow,req,page,instance,proc,queryString) {
//
// setup variables
//
this.obj = $x(obj); // object to put in the partial page
this.proc = proc != null ? proc : 'wwv_flow.show'; // proc to call
this.flow = flow != null ? flow : $x('pFlowId').value; // flowid
this.request = req != null ? req : ''; // request
this.page = page; // page
this.params = ''; // holder for params
this.response = ''; // holder for the response
this.base = null; // holder fot the base url
this.queryString = queryString!= null ? queryString : null ; // holder for passing in f? syntax
this.syncMode = false;
//
// declare methods
//
this.addParam = htmldb_Get_addParam;
this.add = htmldb_Get_addItem;
this.getPartial = htmldb_Get_trimPartialPage;
this.getFull = htmldb_Get_fullReturn;
this.get = htmldb_Get_getData;
this.url = htmldb_Get_getUrl;
this.escape = htmldb_Get_escape;
this.clear = htmldb_Get_clear;
this.sync = htmldb_Get_sync;
this.setNode = setNode;
this.replaceNode = replaceNode
//
// setup the base url
//
var u = window.location.href.indexOf("?") > 0 ?
window.location.href.substring(0,window.location.href.indexOf("?"))
: window.location.href;
this.base = u.substring(0,u.lastIndexOf("/"));
if ( this.proc == null || this.proc == "" )
this.proc = u.substring(u.lastIndexOf("/")+1);
this.base = this.base +"/" + this.proc;
//
// grab the instance form the page form
//
if ( instance == null || instance == "" ) {
var pageInstance = document.getElementById("pInstance");
if ( typeof(pageInstance) == 'object' ) {
this.instance = pageInstance.value;
}
} else {
this.instance = instance;
}
//
// finish setiing up the base url and params
//
if ( ! queryString ) {
this.addParam('p_request', this.request) ;
this.addParam('p_instance', this.instance);
this.addParam('p_flow_id', this.flow);
this.addParam('p_flow_step_id',this.page);
}
function setNode(id) {
this.node = html_GetElement(id);
}
function replaceNode(newNode){
var i=0;
for(i=this.node.childNodes.length-1;i>=0;i--){
this.node.removeChild(this.node.childNodes[i]);
}
this.node.appendChild(newNode);
}
}
function htmldb_Get_sync(s){
this.syncMode=s;
}
function htmldb_Get_clear(val){
this.addParam('p_clear_cache',val);
}
//
// return the queryString
//
function htmldb_Get_getUrl(){
return this.queryString == null ? this.base +'?'+ this.params : this.queryString;
}
function htmldb_Get_escape(val){
// force to be a string
val = val + "";
val = val.replace(/\%/g, "%25");
val = val.replace(/\+/g, "%2B");
val = val.replace(/\ /g, "%20");
val = val.replace(/\./g, "%2E");
val = val.replace(/\*/g, "%2A");
val = val.replace(/\?/g, "%3F");
val = val.replace(/\\/g, "%5C");
val = val.replace(/\//g, "%2F");
val = val.replace(/\>/g, "%3E");
val = val.replace(/\</g, "%3C");
val = val.replace(/\{/g, "%7B");
val = val.replace(/\}/g, "%7D");
val = val.replace(/\~/g, "%7E");
val = val.replace(/\[/g, "%5B");
val = val.replace(/\]/g, "%5D");
val = val.replace(/\`/g, "%60");
val = val.replace(/\;/g, "%3B");
val = val.replace(/\?/g, "%3F");
val = val.replace(/\#/g, "%40");
val = val.replace(/\&/g, "%26");
val = val.replace(/\#/g, "%23");
val = val.replace(/\|/g, "%7C");
val = val.replace(/\^/g, "%5E");
val = val.replace(/\:/g, "%3A");
val = val.replace(/\=/g, "%3D");
val = val.replace(/\$/g, "%24");
//val = val.replace(/\"/g, "%22");
return val;
}
//
// Simple function to add name/value pairs to the url
//
function htmldb_Get_addParam(name,val){
if ( this.params == '' )
this.params = name + '='+ ( val != null ? this.escape(val) : '' );
else
//this.params = this.params + '&'+ name + '='+ ( val != null ? val : '' );
this.params = this.params + '&'+ name + '='+ ( val != null ? this.escape(val) : '' );
return;
}
//
// Simple function to add name/value pairs to the url
//
function htmldb_Get_addItem(name,value){
this.addParam('p_arg_names',name);
this.addParam('p_arg_values',value);
}
//
// funtion strips out the PPR sections and returns that
//
function htmldb_Get_trimPartialPage(startTag,endTag,obj) {
setTimeout(html_processing,1);
if (obj) {this.obj = $x(obj);}
if (!startTag){startTag = '<!--START-->'};
if (!endTag){endTag = '<!--END-->'};
var start = this.response.indexOf(startTag);
var part;
if ( start >0 ) {
this.response = this.response.substring(start+startTag.length);
var end = this.response.indexOf(endTag);
this.response = this.response.substring(0,end);
}
if ( this.obj ) {
if(this.obj.nodeName == 'INPUT'){
if(document.all){
gResult = this.response;
gNode = this.obj;
var ie_HACK = 'htmldb_get_WriteResult()';
setTimeout(ie_HACK,100);
}else{
this.obj.value = this.response;
}
}else{
if(document.all){
gResult = this.response;
gNode = this.obj;
var ie_HACK = 'htmldb_get_WriteResult()';
setTimeout(ie_HACK,100);
}else{
this.obj.innerHTML = this.response;
}
}
}
//window.status = 'Done'
setTimeout(html_Doneprocessing,1);
return this.response;
}
var gResult = null;
var gNode = null
function htmldb_get_WriteResult(){
if(gNode && ( gNode.nodeName == 'INPUT' || gNode.nodeName == 'TEXTAREA')){
gNode.value = gResult;
}else{
gNode.innerHTML = gResult;
}
gResult = null;
gNode = null;
return;
}
//
// function return the full response
//
function htmldb_Get_fullReturn(obj) {
setTimeout(html_processing,1);
if (obj) { this.obj = html_GetElement(obj);}
if ( this.obj ) {
if(this.obj.nodeName == 'INPUT'){
this.obj.value = this.response;
}else{
if(document.all){
gResult = this.response;
gNode = this.obj;
var ie_HACK = 'htmldb_get_WriteResult()';
setTimeout(ie_HACK,10);
}else{
this.obj.innerHTML = this.response;
}
}
}
setTimeout(html_Doneprocessing,1);
return this.response;
}
//
// Perform the actual get from the server
//
function htmldb_Get_getData(mode,startTag,endTag){
html_processing();
var p;
try {
p = new XMLHttpRequest();
} catch (e) {
p = new ActiveXObject("Msxml2.XMLHTTP");
}
try {
var startTime = new Date();
p.open("POST", this.base, this.syncMode);
p.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
p.send(this.queryString == null ? this.params : this.queryString );
this.response = p.responseText;
if ( this.node )
this.replaceNode(p.responseXML);
if ( mode == null || mode =='PPR' ) {
return this.getPartial(startTag,endTag);
} if ( mode == "XML" ) {
setTimeout(html_Doneprocessing,1);
return p.responseXML;
} else {
return this.getFull();
}
} catch (e) {
setTimeout(html_Doneprocessing,1);
return;
}
}
function html_Doneprocessing(){
document.body.style.cursor="default";
}
function html_processing(){
document.body.style.cursor="wait";
}
/*
this adds better aysnc functionality
to the htmldb_Get object
pVar is the function that you want to call when the xmlhttp state changes
in the function specified by pVar the xmlhttp object can be referenced by the variable p
*/
htmldb_Get.prototype.GetAsync = function(pVar){
try{
p = new XMLHttpRequest();
}catch(e){
p = new ActiveXObject("Msxml2.XMLHTTP");
}
try {
var startTime = new Date();
p.open("POST", this.base, true);
if(p) {
p.onreadystatechange = pVar;
p.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
p.send(this.queryString == null ? this.params : this.queryString );
return p;
}
}catch(e){
return false;
}
}
/* PDF OUTPUT */
/*Gets PDF src XML */
function htmldb_ExternalPost(pThis,pRegion,pPostUrl){
var pURL = 'f?p='+html_GetElement('pFlowId').value+':'+html_GetElement('pFlowStepId').value+':'+html_GetElement('pInstance').value+':FLOW_FOP_OUTPUT_R'+pRegion
document.body.innerHTML = document.body.innerHTML + '<div style="display:none;" id="dbaseSecondForm"><form id="xmlFormPost" action="' + pPostUrl + '?ie=.pdf" method="post" target="pdf"><textarea name="vXML" id="vXML" style="width:500px;height:500px;"></textarea></form></div>';
var l_El = html_GetElement('vXML');
var get = new htmldb_Get(l_El,null,null,null,null,'f',pURL.substring(2));
get.get();
get = null;
setTimeout('html_GetElement("xmlFormPost").submit()',10);
return;
}
function $xml_Control(pThis){
this.xsl_string = '<?xml version="1.0"?><xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"><xsl:output method="html"/><xsl:param name="xpath" /><xsl:template match="/"><xsl:copy-of select="//*[#id=$xpath]"/></xsl:template></xsl:stylesheet>';
if(document.all){
this.xsl_object = new ActiveXObject("Msxml2.FreeThreadedDOMDocument.3.0");
this.xsl_object.async=false;
this.xsl_object.loadXML(this.xsl_string)
tmp = new ActiveXObject("Msxml2.XSLTemplate.3.0");
tmp.stylesheet = this.xsl_object;
this.xsl_processor = tmp.createProcessor();
}else{
this.xsl_object = (new DOMParser()).parseFromString(this.xsl_string, "text/xml");
this.xsl_processor = (new XSLTProcessor());
this.xsl_processor.importStylesheet(this.xsl_object);
this.ownerDocument = document.implementation.createDocument("", "test", null);
}
this.xml = pThis;
this.CloneAndPlace = _CloneAndPlace;
return
function _CloneAndPlace(pThis,pThat,pText){
var lThat = $x(pThat);
if(document.all){
this.xsl_processor.addParameter("xpath", pThis);
this.xsl_processor.input = this.xml;
this.xsl_processor.transform;
var newFragment = this.xsl_processor.output;
}else{
this.xsl_processor.setParameter(null, "xpath", pThis);
var newFragment = this.xsl_processor.transformToFragment(this.xml,this.ownerDocument);
}
if(lThat){
if(document.all){
lThat.innerHTML='';
lThat.innerHTML=newFragment;
}else{
lThat.innerHTML='';
lThat.appendChild(newFragment);
}
/*
in IE newFragment will be a string
in FF newFragment will be a dome Node (more useful)
*/
return newFragment;
}
}
}
I'm developing a simple auxiliary class to send requests using XmlHttpRequest (code below). But I cant make it work. At google chrome, for example, I get the error INVALID_STATE_ERR: DOM Exception 11 and at the other browsers I get a status == 0.
//#method XRequest: Object constructor. As this implements a singleton, the object can't be created calling the constructor, GetInstance should be called instead
function XRequest() {
this.XHR = XRequest.CreateXHR();
}
XRequest.instance = null;
//#method static GetInstance: Creates a singleton object of type XRequest. Should be called whenever an object of that type is required.
//#return: an instance of a XRequest object
XRequest.GetInstance = function() {
if(XRequest.instance == null) {
XRequest.instance = new XRequest();
}
return XRequest.instance;
}
//#method static CreateXHR: Implments a basic factory method for creating a XMLHttpRequest object
//#return: XMLHttp object or null
XRequest.CreateXHR = function() {
var xhr = null;
var factory = [
function() { return new XMLHttpRequest(); },
function() { return new ActiveXObject("Msxml2.XMLHTTP"); },
function() { return new ActiveXObject("Microsoft.XMLHTTP"); }
];
for(var i = 0; i < factory.length; ++i) {
var f = factory[i];
xhr = f();
if(xhr) return xhr;
}
return null;
}
XRequest.prototype.SetRequestHeader = function(name, value) {
if(this.XHR) {
this.XHR.setRequestHeader(name, value);
}
}
XRequest.prototype.SendRequest = function(args) {
var async = true;
var type = "";
var url = "";
var username = "";
var password = "";
var body = null;
var success = null;
var failure = null;
for(e in args) {
switch(e) {
case "async":
async = args[e];
break;
case "type":
type = args[e];
break;
case "success":
success = args[e];
break;
case "failure":
failure = args[e];
break;
case "url":
url = args[e];
break;
case "username":
username = args[e];
break;
case "password":
password = args[e];
break;
case "body":
body = args[e];
break;
case "setHeader":
var h = args[e].split(":");
if(h.length == 2) {
this.SetRequestHeader(h[0], h[1]);
}
break;
}
}
var that = this;
this.XHR.onreadystatechange = function() {
alert("readyState == " + that.XHR.readyState + " status == " + that.XHR.status);
if(that.XHR.readyState == 4) {
if(that.XHR.status == 200 || that.XHR.status == 0) {
if(success) success(that.XHR);
} else {
if(failure) failure();
}
}
};
this.XHR.open(type, url, async, username, password);
this.XHR.send(body);
}
Example of usage:
<script language="javascript">
function onLoad() {
var x = XRequest.GetInstance();
x.SendRequest({type:"GET",
setHeader:"Accept:text/html, image/png, image/*, */*",
url: "http://your_server.com/getData?param1=test",
success:onSuccess, failure:onFail
});
}
function onSuccess(obj) {
alert("OK");
}
function onFail() {
alert("Not at this time!");
}
</script>
Problem in this ajax library.
XHR.setRequestHeader() must be called after XHR.open().
// #method XRequest: Object constructor. As this implements a singleton, the object can't be created calling the constructor, GetInstance should be called instead
function XRequest()
{
this.XHR = XRequest.CreateXHR();
}
XRequest.instance = null;
// #method static GetInstance: Creates a singleton object of type XRequest. Should be called whenever an object of that type is required.
// #return: an instance of a XRequest object
XRequest.GetInstance = function()
{
if(XRequest.instance == null)
{
XRequest.instance = new XRequest();
}
return XRequest.instance;
}
// #method static CreateXHR: Implments a basic factory method for creating a XMLHttpRequest object
// #return: XMLHttp object or null
XRequest.CreateXHR = function()
{
var xhr = null;
var factory = [
function() { return new XMLHttpRequest(); },
function() { return new ActiveXObject("Msxml2.XMLHTTP"); },
function() { return new ActiveXObject("Microsoft.XMLHTTP"); }
];
for(var i = 0; i < factory.length; ++i)
{
var f = factory[i];
xhr = f();
if(xhr)
return xhr;
}
return null;
}
XRequest.prototype.SetRequestHeader = function(name, value)
{
if(this.XHR)
{
//alert(name+'|||'+value);
this.XHR.setRequestHeader(name, value);
}
}
XRequest.prototype.SendRequest = function(args)
{
var async = true;
var type = "";
var url = "";
var username = "";
var password = "";
var body = null;
var success = null;
var failure = null;
for(e in args)
{
switch(e)
{
case "async":
async = args[e];
break;
case "type":
type = args[e];
break;
case "success":
success = args[e];
break;
case "failure":
failure = args[e];
break;
case "url":
url = args[e];
break;
case "username":
username = args[e];
break;
case "password":
password = args[e];
break;
case "body":
body = args[e];
break;
}
}
var that = this;
this.XHR.onreadystatechange = function()
{
alert("readyState == " + that.XHR.readyState + " status == " + that.XHR.status);
if(that.XHR.readyState == 4)
{
if(that.XHR.status == 200 || that.XHR.status == 0)
{
if(success)
success(that.XHR);
}
else
{
if(failure)
failure();
}
}
};
this.XHR.open(type, url, async, username, password);
for(e in args)
{
switch(e)
{
case "setHeader":
var h = args[e].split(":");
if(h.length == 2)
{
this.SetRequestHeader(h[0], h[1]);
}
break;
}
}
this.XHR.send(body);
}
Regardless, you can simplify your SendRequest method by creating a mixin instead of using a giant switch.
XRequest.prototype.SendRequest = function(params) {
var defaultParams = {
async: true,
type: "",
url: "",
username: "",
password: "",
body: null,
success: null,
failure: null
};
for ( var i in defaultParams ) {
if ( defaultParams.hasOwnProperty(i) && typeof params[i] == "undefined" ) {
params[i] = defaultParams[i];
}
}
var that = this;
this.XHR.onreadystatechange = function() {
if ( that.XHR.readyState == 4 ) {
if ( that.XHR.status == 200 || that.XHR.status == 0 ) {
if ( params.success ) {
params.success(that.XHR);
}
} else {
if ( params.failure ) {
params.failure();
}
}
}
};
this.XHR.open(
params.type, parms.url, params.async, params.username, params.password
);
// It doesn't make sense to have a for/switch here when you're only handling
// one case
if ( params.setHeader ) {
var h = params.setHeader.split(":");
if ( h.length == 2) {
this.SetRequestHeader(h[0], h[1]);
}
}
this.XHR.send(params.body);
};
Also be careful: your existing for..in loops have two distinct problems:
You're not using var and causing a global to be created: for (e in args) should be for (var e in args)
Whenever you use for..in, you should always check to make sure that each key is a direct member of the object, and not something inherited inadvertently through prototype
.
for ( var i in obj ) {
if ( obj.hasOwnProperty(i) ) {
// do stuff here
}
}
Usually this error occurs with the XMLHttpRequest when you call the open method with async = true, or you leave the async parameter undefined so it defaults to asynchronous, and then you access the status or responseText properties. Those properties are only available after you do a synchronous call, or on the readyState becoming ready (once the asynchronous call responds). I suggest you first try with async = false, and then switch to it being true and use the onReadyStateChange.
In my case the error occurred when i tried to access xhr.statusText within the xhr.onreadystatechange method, however retrieving xhr.readyState went just fine.