Hey all I'm trying to get a window populated with a table view that is populated from a network function in Titanium Studio, build: 2.1.1.201207271312. I have the data being fetched properlybut the problem is that the program continues to run without waiting for the table view to be populated properly. Here's the code:
ui.js:
bs.ui.createTransitRoutesListWindow = function() {
var winbsRoutesList = Titanium.UI.createWindow({
});
var tv2 = Ti.UI.createTableView();
tv2 = bs.ui.createbsRouteListTableView();
winbsRoutesList.add(tv2);
};
bs.ui.createbsRouteListTableView = function() {
var tv = Ti.UI.createTableView();
Ti.API.info('populating data');
var busStopList = bs.db.routeStopList();
tv.setData(busStopList);
return tv;
};
db.js:
bs.db.routeStopList = function() {
var stoplist = [];
bs.net.getRoutes(function(data) {
Ti.API.info('data length: '+data.length);
for (var i = 0;i<data.length;i++) {
stoplist.push({
title:data[i].stopName,
id: i
});
}
});
return stoplist;
}
network.js
bs.net.getRoutes = function(_cb) {
var xhr = Titanium.Network.createHTTPClient();
xhr.onload = function() {
_cb(JSON.parse(this.responseText));
Ti.API.info(this.responseText)
};
xhr.onerror = function(event) {
}
xhr.open("GET","<URL to valid JSON>", true);
//+ Ti.App.Properties.getString('currentBus','This is a string default')
xhr.send();
};
bussearch.net.getRoutes() is an AJAX operation and thus it is asynchronous. This means that the code will NOT wait for it to complete. The code will proceed while the response is going. The time it will respond is not known also.
If you want to do something after the data returns, you should do everything in the callback instead or create deferred objects like jQuery (which are basically callback containers).
//db.js
bussearch.db.routeStopList = function(callback) {
var stoplist = [];
bussearch.net.getRoutes(function(data) {
....
callback.call(this,stoplist);
});
}
//ui.js
bussearch.ui.createBussearchRouteListTableView = function(callback) {
var tv = Ti.UI.createTableView();
Ti.API.info('populating data');
bussearch.db.routeStopList(function(busStopList){
tv.setData(busStopList);
callback.call(this,tv);
});
};
//calling createBussearchRouteListTableView()
createBussearchRouteListTableView(function(tv){
//tv in here is the data
//do inside here what you want to do to tv after it's retrieved
});
Related
Trying to capture response of a async request in dojo/aspect before() event before handing it off to the original method as below:
aspect.before(ecm.model.SearchTemplate.prototype, "_searchCompleted", function(response, callback, teamspace){
var args = [];
if(response.num_results==0 && isValidQuery){
var args = [];
var requestParams = {};
requestParams.repositoryId = this.repository.id;
requestParams.query = query;
Request.invokePluginService("samplePlugin", "sampleService",
{
requestParams: requestParams,
requestCompleteCallback: lang.hitch(this, function(resp) { // success
//call stack doesnt enter this code block before returning params to the original
//function
resp.repository = this.repository;
args.push(resp);
args.push(callback);
args.push(teamspace);
})
}
);
return args; //args is empty as the response is not captured here yet.
}
});
aspect.around is what you're looking for. It will give you a handle to the original function you can call at will (thus, async at any time you're ready - or never at all).
aspect.around(ecm.model.SearchTemplate.prototype, "_searchCompleted", function advisingFunction(original_searchCompleted){
return function(response, callback, teamspace){
var args = [];
if(response.num_results==0 && isValidQuery){
var args = [];
var requestParams = {};
requestParams.repositoryId = this.repository.id;
requestParams.query = query;
Request.invokePluginService("samplePlugin", "sampleService",
{
requestParams: requestParams,
requestCompleteCallback: lang.hitch(this, function(resp) { // success
//call stack doesnt enter this code block before returning params to the original
//function
resp.repository = this.repository;
args.push(resp);
args.push(callback);
args.push(teamspace);
original_searchCompleted.apply(this,args);
})
}
);
}
}
});
I'm running a Vue script with a text box and submit button, I'm calling an api to POST what I write in the textbox to the api and to return information back from the API, I'm getting this error mentioned in the title eventhough I've written the Javascript functions in vue as it should be?
With the script I'm first setting up a new XMLHttpRequest, initiating the header and api key for both GET and POST methods. I've then created 2 functions to get the data from the textbox and send them to the API, then making another button with the other function to send back the data.
I went through this approach because I kept getting a CORS issue and the API needed me to declare an access control origin header, is there anything I've done wrong with this code? Any help would be greatly appreciated
<script>
export default {
name: 'ProperForm'
}
methods: {
StartClient: function () {
this.get = function(Url, Callback){
var aHttpRequest = new XMLHttpRequest();
aHttpRequest.onreadystatechange = function() {
if (aHttpRequest.readyState == 4 && aHttpRequest.status == 200)
Callback(aHttpRequest.responseText);
}
aHttpRequest.open("GET", Url, true);
aHttpRequest.setRequestHeader("X-Api-Key", "eVnbxBPfn01kuoJIdfgi46TiYNv8AIip1r3WbjsX");
aHttpRequest.send(null);
}
this.post = function(Url, message, Callback) {
var aHttpRequest = new XMLHttpRequest();
aHttpRequest.onreadystatechange = function() {
if (aHttpRequest.readyState == 4 && aHttpRequest.status == 200)
Callback(aHttpRequest.responseText);
}
aHttpRequest.open("POST", Url, true);
aHttpRequest.setRequestHeader("x-api-key", "eVnbxBPfn01kuoJIdfgi46TiYNv8AIip1r3WbjsX");
aHttpRequest.send(message);
}
}
var client = new StartClient();
submitData: function () {
document.getElementById('inputBox').disabled = true;
var targetInputButton = document.getElementById("inputBox").value;
var message = '{"targetInputButton":"' + targetInputButton + '"}';
client.post('https://le75bkfcmg.execute-api.eu-west-2.amazonaws.com/dev/start-trace', message, function(response) {
document.getElementById('jobId').innerHTML = response;
});
}
sendBackData: function () {
var jobId = document.getElementById("jobId").innerHTML;
var message = '{"jobId":"' + jobId + '"}';
client.post('https://le75bkfcmg.execute-api.eu-west-2.amazonaws.com/dev/check-trace', message, function(response) {
document.getElementById('report').innerHTML = response;
});
}
}
</script>
New way I wrote var client:
StartClient: function () {
var client
},
You need put your methods object inside export and split the methods to comma
<script>
export default {
name: 'name',
methods:{
foo(){
},
bar(){
}
}
}
UPD: var client = new StartClient();
defined outside the method
I have been having some issues with opening multiple webpages in phantomjs, I am first opening a website which contains a few links, which I want to open as well, and save a piece of text from each URL to my jobs_list which has many objects inside of it. And after all the URL's have been run, I want to exit phantomjs. But as it is right now it never exits, and I have trouble recieving data from second function.
var webPage = require('webpage');
var page = webPage.create();
var jobs_list = [];
page.open('url', function (status) {
page.includeJs("http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js", function() {
page.onConsoleMessage = function(msg) {
console.log(msg);
};
var list = page.evaluate(function() {
var jobs = [];
var job;
$('.test').each(function(){
$(this).find('span').each(function(){
var job_link = $(this).find('a');
var url = job_link.attr("href");
job = {title : job_link.text(), url : url, location : ""};
jobs.push(job);
})
});
return jobs;
});
var i = 0;
jobs_list = list;
next_page(i);
});
});
function next_page(i){
if (i <= (jobs_list.length-1)) {
var current_job = jobs_list[i];
var url = current_job.url;
page.open(url, function (status) {
page.includeJs("http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js", function () {
var location = page.evaluate(function() {
var job_location;
$('.job-location').each(function(){
$(this).find('li').each(function(){
job_location = $(this).text();
})
})
console.log(job_location);
return job_location;
});
jobs_list[i].location = location;
if(i == (jobs_list.length-1)) {
phantom.exit(0);
}
});
});
console.log(i, current_job.title);
next_page(++i);
}
}
The problem is that the page.open call is asynchronous. If you look closely to your next_page function it can be shortened to this:
function next_page(i){
if (i <= (jobs_list.length-1)) {
var current_job = jobs_list[i];
var url = current_job.url;
page.open(url, function (status) {
...
});
console.log(i, current_job.title);
next_page(++i);
}
}
It means that next_page(++i); is executed before page.open(url, ...) even managed to load the first HTML content. This call leads to the next page.open(url, ...) being executed immediately, thus overwriting the previous request. And you're never going to get any data this way.
You have to do two things:
move the next_page(++i); call where the execution of one page is finished
reduce the number of condition checking
I propose:
function next_page(i){
if (i <= (jobs_list.length-1)) {
var current_job = jobs_list[i];
var url = current_job.url;
page.open(url, function (status) {
page.includeJs("http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js", function () {
var location = page.evaluate(function() {
var job_location;
$('.job-location').each(function(){
$(this).find('li').each(function(){
job_location = $(this).text();
})
})
console.log(job_location);
return job_location;
});
jobs_list[i].location = location;
console.log(i, current_job.title);
next_page(++i);
});
});
} else {
phantom.exit(0);
}
}
That's quite an old version of jQuery. Perhaps you want to load a newer version. If the page already has jQuery included, you will likely break the page by loading another jQuery into it. Don't load an additional jQuery version at all in this case.
I have a meteor code that calls an method on the server. The server code executes an API call to the USDA and puts the resulting json set into a array list. The problem is that after the Meteor.call on the client side, it hangs.
var ndbItems = [];
if (Meteor.isClient) {
Template.body.events({
"submit .searchNDB" : function(event) {
ndbItems = [];
var ndbsearch = event.target.text.value;
Meteor.call('getNDB', ndbsearch);
console.log("This doesn't show in console.");
return false;
}
});
}
if (Meteor.isServer) {
Meteor.methods({
'getNDB' : function(searchNDB) {
this.unblock();
var ndbresult = HTTP.call("GET", "http://api.nal.usda.gov/ndb/search/",
{params: {api_key: "KEY", format: "json", q: searchNDB}});
var ndbJSON = JSON.parse(ndbresult.content);
var ndbItem = ndbJSON.list.item;
for (var i in ndbItem) {
var tempObj = {};
tempObj['ndbno'] = ndbItem[i].ndbno;
tempObj['name'] = ndbItem[i].name;
tempObj['group'] = ndbItem[i].group;
ndbItems.push(tempObj);
}
console.log(ndbItems); //This shows in console.
console.log("This also shows in console.");
}
});
}
After the call to the server and the API returns data to the console and writes it to the array, it doesn't process the console.log on the client side 1 line below the method call. How can I fix this?
You forgot to give your client side call a callback function. Method calls on the client are async, because there are no fibers on the client. Use this:
if (Meteor.isClient) {
Template.body.events({
"submit .searchNDB" : function(event) {
ndbItems = [];
var ndbsearch = event.target.text.value;
Meteor.call('getNDB', ndbsearch, function(err, result) {
console.log("This will show in console once the call comes back.");
});
return false;
}
});
}
EDIT:
You must also call return on the server:
if (Meteor.isServer) {
Meteor.methods({
'getNDB' : function(searchNDB) {
this.unblock();
var ndbresult = HTTP.call("GET", "http://api.nal.usda.gov/ndb/search/",
{params: {api_key: "KEY", format: "json", q: searchNDB}});
....
console.log("This also shows in console.");
return;
}
});
}
I am using indexedDB to store some offline data. In my code there is a loop inserting values to a store object:
function Insert(){
for(var i in list)
InsertList(list[i]);
alert("successful");
}
function InsertList(str){
var trans = LocalDB.indexedDB.db.transaction(StoreList, IDBTransaction.READ_WRITE);
var store = trans.objectStore(StoreList);
var data = {
"item": str};
var request = store.put(data);
request.onsuccess = function (e) { };
request.onerror = function (e) { alert("Error inserting"); };
}
The alert message will show before the loop executes, and if the page is refreshed or closed immediately after I close the alert message, some values are not inserted into the list because the loop was interrupted. So how can I know that the loop has ended and then give a successful message? Thanks.
The indexeddb API is async. This means you can only get feedback if something ended using a callback method in the success.
In your case I would work differently and insert everything in one transaction. When the transaction is completed, you get a callback. If that is called you can be sure everything is saved and the inserts are completed.
function Insert(){
var trans = LocalDB.indexedDB.db.transaction(StoreList, IDBTransaction.READ_WRITE);
var store = trans.objectStore(StoreList);
for(var i in list)
{
var data = { "item": list[i]};
var request = store.put(data);
request.onsuccess = function (e) { };
request.onerror = function (e) { alert("Error inserting"); };
}
trans.oncomplete = function ()
{
alert("successful");
}
}