Parsing Json with Promise in Tableau - javascript

I'm working on tableau and I have to build my own web data connector.
I wrote it and it works perfectly on Chrome.
But when I use it into Tableau I get the foolowing error :
ReferenceError: Can't find variable: Promise file: http://localhost:9000/json-connector line: 246
My connector is devided in two parts. The first part call a web service to get a list of destinations and fill two lists with their names. The second part call another web service to get every paths beetween two selected destinations.
The error occured while I want to get the first list. I want to insist that it works on chrome, but not in tableau.
The portion of code where the error occured :
var getJSON = function(url) {
return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open('get', url, true);
xhr.responseType = 'json';
xhr.onload = function() {
var status = xhr.status;
if (status == 200) {
resolve(xhr.response);
} else {
console.log("Something went wrong with the destination")
reject(status);
}
};
xhr.send();
});
};
I think that tableau doesn't support Promise. But I don't know how to make a work around. Thank's a lot for your help !
This is how I use this function :
getJSON('http://localhost:9000/stations').then(function(data) {
//alert('Your Json result is: ' + data.result); //you can comment this, i used it to debug
//result.innerText = JSON.stringify(data); //display the result in an HTML element
console.log("starting parsing on : " + data.length);
var listArrival = document.getElementById('Arrival'); //get the list where you want to add options
var listDeparture = document.getElementById('Departure');
if(listArrival == null || listDeparture == null) console.error("Impossible to retrieve the list")
var op;
var addedStations = [];
for(var i = 0; i < data.length ; i++){
var obj = data[i];
var overflowControler = 0;
for(var key in obj){
console.log(key + '=' + obj[key]);
if(key == 'name' && addedStations.indexOf(obj[key]) == -1){
op = new Option(obj[key], obj['nlc'], true);
op2 = new Option(obj[key], obj['nlc'], true);
if(op == null) console.error("Impossible to create the new option")
listArrival.add(op);
listDeparture.add(op2);
addedStations.push(obj[key]);
}
overflowControler ++;
if(overflowControler > maxLengthOfEachRecordFromJson) break; // overflow control
}
if(i > maxStationsRecordNumberFromJson) break; //overflow control
}
}, function(status) { //error detection....
alert('Something went wrong.');
});

As suggested by Tomalak I added a library to my script and Tableau is able to use Promise.
<script src="https://cdnjs.cloudflare.com/ajax/libs/es6-promise/3.2.1/es6-promise.min.js" type="text/javascript"></script>
I didn't make other changes in the code.

Related

How can i catch the error when the api reaches its daily limit in JS?

I am trying to catch the specific error when a certain API key expires or it reaches its daily response limit(assuming 1000 per day).
const moviesearchEngine=()=>{
let searchBox = document.querySelector('.searchBox');
let movieTitle = document.querySelector('.movieTitle');
let yearofRelease = document.querySelector('.yearofRelease');
let genre = document.querySelector('.genre');
let director = document.querySelector('.director');
let plot = document.querySelector('.plot');
const apiCall = ()=>{
let params = new URLSearchParams({
t:searchBox.value,
apikey:`key`
})
let api = `http://www.omdbapi.com/?${params}`;
//fetching the api orelse showing the error
fetch(api).then((response)=>{
return response.json();
}).then((data)=>{
//assigning the data to variable
console.log(data)
})
}
apiCall();
}
Please Go through your desired API's documention and you would be looking for this sort of information mentioned in the Usage limits section of this api page. If you fail to find anything useful then please contact the support of your desired API.
Then you can proceed like this -
var endpoint = 'http://ip-api.com/json/?fields=status,message,countryCode';
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var response = JSON.parse(this.responseText);
if(response.status !== 'success') {
console.log('query failed: ' + response.message);
return
}
// Redirect
if(response.countryCode == "US") {
window.location.replace("https://google.com/");
}
if(response.countryCode == "CA") {
window.location.replace("https://google.ca/");
}
}
};
xhr.open('GET', endpoint, true);
xhr.send();
Source

My jQuery Ajax Call to pure Javascript

I asked about 5 month ago about rewriting my ajax call in pure Javascript. Here the original post: https://stackoverflow.com/questions/35415812/need-help-to-rewrite-my-jquery-ajax-call-to-plain-javascript
I never thought about to rewrite the script completely because it works but now i need to rewrite the whole script to plain js. I already startet.
Here is the jQUery/JS mix:
var cc = document.getElementsByClassName("cart-count");
var wc = document.getElementsByClassName("wishlist-count");
var url = wp_ajax.ajax_url;
var data = {
action: 'get_counts'
};
// JQUERY JS mixed VERSION
$.ajax({
type: 'POST',
url: url,
data: data,
success: function (data) {
var counts = JSON.parse(data);
console.log(data);
for(var i = 0; i < cc.length; i++){
cc[i].innerText=counts["cartCount"];
}
for(var i = 0; i < wc.length; i++){
wc[i].innerText=counts["wlCount"];
}
}
});
console says:
{"cartCount":"(1)","wlCount":"(3)"}
That's right!
But now i tried to rewrite the rest. Here the latest:
var cc = document.getElementsByClassName("cart-count");
var wc = document.getElementsByClassName("wishlist-count");
var url = wp_ajax.ajax_url;
var data = {
action: 'get_counts'
};
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState == XMLHttpRequest.DONE) {
if (xmlhttp.status == 200) {
//document.getElementById("myDiv").innerHTML = xmlhttp.responseText;
var counts = data
console.log(data);
for(var i = 0; i < cc.length; i++){
cc[i].innerText=counts["cartCount"];
}
for(var i = 0; i < wc.length; i++){
wc[i].innerText=counts["wlCount"];
}
console.log('done');
} else if (xmlhttp.status == 400) {
console.log('There was an error 400');
} else {
console.log('something else other than 200 was returned');
}
}
};
xmlhttp.open('POST', url, true);
xmlhttp.send(data);
It does't work. The console gives me not the value, just the var:
Object {action: "get_counts"}
My question/problem: How can i get the data action values without the jQuery ajax? Please no questions like "why not jQuery?".
Thanks for all help!!! Sorry for my english.
UPDATE:
I got it!
jQuery:
var data = {
action: 'get_counts'
};
JS:
url + '?action=get_counts'
add this
var data = JSON.parse(xmlhttp.responseText);//you have to parse result
before this
var counts = data
console.log(data);
You are not evaluating the AJAX response data, but the local variable data which is set above the AJAX call:
var data = {
action: 'get_counts'
};
You need to parse the AJAX response instead:
if (xmlhttp.status == 200) {
console.log( JSON.parse(xmlhttp.response) )
}
See: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/response
Its happening because Ajax is async request which the browser handers in a different thread than the one which is processing your code. Normally jquery and other similar frameworks have callback methods defined for that but in pure JS implementation you can use
xmlhttp.responseText
to fetch the output once the request is done

XMLHttpRequest in for loop

I am trying to make several server requests inside a for loop. I found this question and implemented the suggested solution. However it doesn't seem to work.
for (var i = 1; i <= 10; i++)
{
(function(i) {
if(<some conditions>)
{
if (window.XMLHttpRequest) {
// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp[i]=new XMLHttpRequest();
} else { // code for IE6, IE5
xmlhttp[i]=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp[i].onreadystatechange=function() {
if (xmlhttp[i].readyState==4 && xmlhttp[i].status==200) {
document.getElementById("preselection").innerHTML=xmlhttp[i].responseText;
}
}
xmlhttp[i].open("GET","getBuoys.php?q="+i,true);
xmlhttp[i].send();
}
})(i);
}
If I remove the for loop and change all xmlhttp[i] to xmlhttp, everything works just fine for one element, but I can't make several requests. Thanks in advance for any suggestions.
Try the snippet below
// JavaScript
window.onload = function(){
var f = (function(){
var xhr = [], i;
for(i = 0; i < 3; i++){ //for loop
(function(i){
xhr[i] = new XMLHttpRequest();
url = "closure.php?data=" + i;
xhr[i].open("GET", url, true);
xhr[i].onreadystatechange = function(){
if (xhr[i].readyState === 4 && xhr[i].status === 200){
console.log('Response from request ' + i + ' [ ' + xhr[i].responseText + ']');
}
};
xhr[i].send();
})(i);
}
})();
};
// PHP [closure.php]
echo "Hello Kitty -> " . $_GET["data"];
Response
Response from request 0 [ Hello Kitty -> 0]
Response from request 1 [ Hello Kitty -> 1]
Response from request 2 [ Hello Kitty -> 2]
First thing first, that's awful formatting. A small request to keep it a bit more parseable in future please.
We can clean this up though.
var XMLHttpRequest
= XMLHttpRequest || require('xmlhttprequest').XMLHttpRequest;
// Makes a request for 4 buoy page responses.
requestAllBuoys(4, function(requests) {
console.log('Got results!');
// Take out the responses, they are collected in the order they were
// requested.
responses = requests.map(function(request) {
return request.responseText;
});
// Left to you to implement- I don't know what you're going to do with
// your page!
updateDom(responses);
});
// Makes request to all buoy url's, calling the given callback once
// all have completed with an array of xmlRequests.
function requestAllBuoys (n, cb) {
var latch = makeLatch(n, cb);
makeBuoyURLTo(n).map(function (url, i) {
startXMLRequest('GET', url, latch.bind(undefined, i));
});
}
// Generates a latch function, that will execute the given callback
// only once the function it returns has been called n times.
function makeLatch (n, cb) {
var remaining = n,
results = [],
countDown;
countDown = function (i, result) {
results[i] = result;
if (--remaining == 0 && typeof cb == 'function') {
cb(results);
}
}
return countDown;
}
// Generates an array of buoy URL's from 1 to n.
function makeBuoyURLTo (n) {
var i, buoyUrls = [];
for (i = 1; i <= n; i++) {
buoyUrls.push('getBuoys.php?q=' + i);
}
return buoyUrls;
}
// Create and initiate an XMLRequest, with the given method to the given url.
// The optional callback will be called on successful completion.
function startXMLRequest (method, url, cb) {
var xmlRequest = createXMLRequest();
xmlRequest.onreadystatechange = function () {
if (isXMLFinished(xmlRequest)) {
if (cb && typeof cb == 'function') {
cb(xmlRequest, method, url);
}
}
}
xmlRequest.open(method, url, true);
xmlRequest.send();
return xmlRequest;
}
// Initiates an XMLRequest from either HTML5 native, or MS ActiveX depending
// on what is available.
function createXMLRequest () {
var xmlRequest;
if (XMLHttpRequest) {
xmlRequest = new XMLHttpRequest();
} else {
xmlRequest = new ActiveXObject('Microsoft.XMLHTTP');
}
return xmlRequest;
}
// Verifies that XMLRequest has finished, with a status 200 (OK).
function isXMLFinished (xmlRequest) {
return (xmlRequest.readyState == 4) && (xmlRequest.status == 200);
}
This may seem longer, but it makes things infinitely clearer, and the time you spent making it so is time you don't spend debugging.
It also allows you to access the final result together, in the order that they came as a standard array. This is the main added bulk.
I would say you have a good idea of what you're actually doing here, as to me the only thing about your code that wouldn't work is the updating of the dom (surely you'll just be assigning them rapidly all into the same element? replacing each other each time...).
Have a look at this answer about handling async callbacks if you're still struggling. But please, for your own sake, keep your code cleaner.

Find current SharePoint user with Javascript code

Hy
I need to find the current user from my SharePoint.
I have tried many things :
SP.Utilities.PrincipalInfo.get_loginName()
_spPageContextInfo.userId
...
At all times, I have the same result Undefined =(
When using CSOM API to retrieve current user object,wrap your code inside
SP.SOD.executeOrDelayUntilScriptLoaded method to make sure that the specified code is executed after SharePoint JS library (sp.js) is loaded:
SP.SOD.executeOrDelayUntilScriptLoaded(function(){
//your code goes here..
}, 'sp.js');
How to retrieve current user object using CSOM API
function getCurrentUser(success,error)
{
var ctx = SP.ClientContext.get_current();
var web = ctx.get_web();
var currentUser = web.get_currentUser();
ctx.load(currentUser);
ctx.executeQueryAsync(function(){
success(currentUser);
},
error);
}
Usage
SP.SOD.executeOrDelayUntilScriptLoaded(function(){
getCurrentUser(
function(currentUser){
console.log(currentUser.get_loginName());
},
function(sender, args)
{
console.log('Request failed ' + args.get_message() + ':'+ args.get_stackTrace());
});
}, 'sp.js');
The answer is probably here. The only thing i changed is getting LoginName instead of Title:
https://stackoverflow.com/a/21002895/1680288
var userid= _spPageContextInfo.userId;
var requestUri = _spPageContextInfo.webAbsoluteUrl + "/_api/web/getuserbyid(" + userid + ")";
var requestHeaders = { "accept" : "application/json;odata=verbose" };
$.ajax({
url : requestUri,
contentType : "application/json;odata=verbose",
headers : requestHeaders,
success : onSuccess,
error : onError
});
function onSuccess(data, request){
var loginName = data.d.LoginName;
alert(loginName);
}
function onError(error) {
alert("error");
}
If you are getting undefined.. Maybe you are not authenticated or did not include some relevant javascript files in your master page.
Without jquery:
var userid= _spPageContextInfo.userId;
var requestUri = _spPageContextInfo.webAbsoluteUrl + "/_api/web/getuserbyid(" + userid + ")";
function createXMLHttp() {
//If XMLHttpRequest is available then using it
if (typeof XMLHttpRequest !== undefined) {
return new XMLHttpRequest;
//if window.ActiveXObject is available than the user is using IE...so we have to create the newest version XMLHttp object
} else if (window.ActiveXObject) {
var ieXMLHttpVersions = ['MSXML2.XMLHttp.5.0', 'MSXML2.XMLHttp.4.0', 'MSXML2.XMLHttp.3.0', 'MSXML2.XMLHttp', 'Microsoft.XMLHttp'],
xmlHttp;
//In this array we are starting from the first element (newest version) and trying to create it. If there is an
//exception thrown we are handling it (and doing nothing ^^)
for (var i = 0; i < ieXMLHttpVersions.length; i++) {
try {
xmlHttp = new ActiveXObject(ieXMLHttpVersions[i]);
return xmlHttp;
} catch (e) {
}
}
}
}
function getData() {
var xmlHttp = createXMLHttp();
xmlHttp.open('get', requestUri , true);
xmlHttp.setRequestHeader("Content-Type", "application/json;odata=verbose");
xmlHttp.setRequestHeader("accept", "application/json;odata=verbose");
xmlHttp.send(null);
xmlHttp.onreadystatechange = function() {
if (xmlHttp.readyState === 4) {
if (xmlHttp.status === 200) {
var data = JSON.parse(xmlHttp.responseText);
var loginName = data.d.LoginName;
alert(loginName);
} else {
}
} else {
//still processing
}
};
}
getData();

Select an Option based on req.responseText

I don't know if I am just thinking too hard about this or what. I just want to be able to select a specific option based on the result I get from a call. Currently call produces City, State, Country based on Zip code. The response from the GET is "Sacramento | CA | United States" I can easily put the responses into input boxes, but I can't figure out how to select an option based on the response. Is this possible? I've been looking through some of the method properties and i'm not really seeing anything that I can use.
Here is the Get script.
<script type="text/javascript">
var req;
var oldData;
var doesNotSupport = true;
function getAddress(url, number)
{
if (number == "" || oldData == number || !doesNotSupport)
return;
oldData = number;
document.getElementById('city').value = "Searching ...";
document.getElementById('state').value = "Searching ...";
document.getElementById('country').value = "Searching ...";
if (window.XMLHttpRequest) {
req = new XMLHttpRequest;
} else if (window.ActiveXObject) {
req = new ActiveXObject("Microsoft.XMLHTTP");
}
if (req) {
req.onreadystatechange = processReqChange;
req.open("GET", url + '?number=' + number + '&zip=' + number, true);
req.send(null);
} else {
alert("Your browser does not support XMLHttpRequest technology!");
doesNotSupport = false;
}
}
</script>
Here is the Response script
<script type="text/javascript">
function processReqChange() {
// only if req shows "loaded"
if (req.readyState == 4) {
// only if "OK"
if (req.status == 200) {
var Result = req.responseText.split("|");
document.getElementById('city').value = Result[0];
document.getElementById('state').value = Result[1];
This is the problem child.
document.getElementById('country').value = Result[2];
} else {
alert("There was a problem retrieving the XML data:\n" + req.statusText);
}
}
}
</script>
option setup
<option name="(abbr.)" value="(full name)">Full Name</option>
i.e.
<option name="CA" value="California">California</option>
I'm just looking for something to replace the .value property. Something like document.getElementById('state').childNode.attribute.name = Result[1] or something.
Here is a link to the full page file http://ge.tt/99dJ1J9?c
The problem is that you do not have the abbrev for the state in option value and the response contains the abbrev.
Also, i would recommend you some javascript framework. It would help you very much with common taks like Ajax, form validation and so on.
Just google javascript framework and find one that would fit your needs best :-)
Use this to set the value in your SELECT object (below code is for city):
var selObject = document.getElementById('city_select_id');
selObject.value = document.getElementById('city').value; //value received in the response

Categories