Get an array to transfer data outside a function.

You must Login before you can answer or comment on any questions.

I'm collecting longitude and latitude from a xml file into an array, in this case annotation. Inside the function and for loop it collects the information correct but as soon as I get it outside I loose it. I tried several threads here and other suggestions and nothing worked. Someone told me to declare the array before the function and I did, nothing. Someone told me to to push it out from the function, nothing. Please help.

Titanium.UI.setBackgroundImage('#000');
 
var win = Titanium.UI.createWindow({ 
    navBarHidden:true
});
win.open();
 
var tableView = Titanium.UI.createTableView({
    backgroundColor:'white',
    separatorStyle: Titanium.UI.iPhone.TableViewSeparatorStyle.NONE,
    separatorColor: 'transparent'
});
 
var annotations = new Array(); 
 
var url ="http://www.test.se/test.xml"; //  rss feed url
var xhr = Titanium.Network.createHTTPClient();
 
win.add(tableView);
 
xhr.onload = function() {
    var data = [];
 
    var doc = this.responseXML.documentElement;
 
    var items = doc.getElementsByTagName("item");
    for (var i=0;i<items.length;i++) {
        //
        var row = Ti.UI.createTableViewRow();
        row.selectedBackgroundColor = '#fff';
        row.height = 20;
        //
        var title = Ti.UI.createLabel({
            color:'#000',
            font:{fontSize:12, fontFamily:'Helvetica Neue'},
            left:10,
            top:2,
            height:'auto',
            width:'auto',
            text:items.item(i).getElementsByTagName("title").item(0).text
        });
        row.add(title);
        //
        var locationname = Ti.UI.createLabel({
            color:'#000',
            font:{fontSize:12, fontFamily:'Helvetica Neue'},
            left:110,
            top:2,
            height:'auto',
            width:'auto',
            text:items.item(i).getElementsByTagName("locationname").item(0).text
        });
        row.add(locationname);
        //
        var latitude = Ti.UI.createLabel({
            color:'#000',
            font:{fontSize:12, fontFamily:'Helvetica Neue'},
            left:210,
            top:2,
            height:'auto',
            width:'auto',
            text:items.item(i).getElementsByTagName("latitude").item(0).text
        });      
        row.add(latitude);
 
    ///////
        var longi = items.item(i).getElementsByTagName("latitude").item(0).text
        var lati = items.item(i).getElementsByTagName("longitude").item(0).text
 
    annotations = {latitude:lati,longitude:longi};
 
    //This one works, I get the correct info when it is uncomment.
    Ti.API.info('Inside function: '+annotations); 
    //////
        data.push(row);
    }
 
    tableView.setData(data);
 
};
 
xhr.onerror = function(e) {
    alert('Network error '+e.error);
};
 
xhr.open('GET',url);
 
xhr.send();
 
//I need the information from annotations from 
//inside the function. This doesnt work. The info I get is [INFO] ()
Ti.API.info('Outside function: '+annotations);
 
var annotationObject = [];
for(var i=0; i<annotations.length; i++){
    annotationObject[i] = Titanium.Map.createAnnotation({
        latitude:annotations[i].latitude,
        longitude:annotations[i].longitude,
        title:annotations[i].title,
        subtitle:annotations[i].subtitle,
        animate:true,
        customProperty:annotations[i].customProperty
    });
}
 
var mapview = Titanium.Map.createView({
    mapType: Titanium.Map.STANDARD_TYPE,
    region:{latitudeDelta:3, longitudeDelta:3},
    animate:true,
    regionFit:true,
    userLocation:true,
    height: 300,
    width:320,
    bottom:0,
    userLocation:true,
    annotations:annotationObject
});
 
mapview.addEventListener("click",function(e){
    alert(e.annotation.customProperty);
});
 
win.add(mapview);

4 Answers

The problem is that the network request is asynchronous. You can't just call send() and start using the data. It doesn't work that way. send() doesn't block while the request/response are processed. Your line:

Ti.API.info('Outside function: '+annotations);
will most likely run LONG before the request comes back.

Please see a lengthy discussion on the subject in this thread.

— answered 9 months ago by Jason Priebe
answer permalink
4 Comments
  • Yes it does. I get the Outside before the inside. I will look into the thread u posted. Thx.

    — commented 9 months ago by Martin Andersson

  • It made sense, but there were no recommendations what to do. But I asked the following questions in that thread now.

    — commented 9 months ago by Martin Andersson

  • You just asked me the questions -- I was the one who answered in that thread. But see my answer there, with a general example of a CommonJS class module that uses the results of a network request to initialize its UI.

    You can't get around the fact that the request is asynchronous. Don't waste time looking for a workaround. It will get you nowhere and it will waste a lot of your time.

    What Matt and Josh are trying to tell you is that you should use the data to initialize your map's annotations while you are inside the onload() function.

    Any code you add after the send() will happen before the results are back from the server, and thus the data will not be available to that code.

    You can, of course, create another function and your onload() can pass the data to that function (as I show in my example).

    — commented 9 months ago by Jason Priebe

  • Show 1 more comment

not tested but i think this is the gist of what you are trying to do.

Titanium.UI.setBackgroundImage('#000');
 
var win = Titanium.UI.createWindow({ 
    navBarHidden:true
});
 
var tableView = Titanium.UI.createTableView({
    backgroundColor:'white',
    separatorStyle: Titanium.UI.iPhone.TableViewSeparatorStyle.NONE,
    separatorColor: 'transparent'
});
 
win.add(tableView);
 
var mapview = Titanium.Map.createView({
    mapType: Titanium.Map.STANDARD_TYPE,
    region:{latitudeDelta:3, longitudeDelta:3},
    animate:true,
    regionFit:true,
    userLocation:true,
    height: 300,
    width:320,
    bottom:0
});
 
mapview.addEventListener("click",function(e){
    alert(e.annotation.customProperty);
});
 
win.add(mapview);
 
var url ="http://www.test.se/test.xml"; //  rss feed url
var xhr = Titanium.Network.createHTTPClient();
 
xhr.onload = function() {
 
    // if you want to clear previous annotations
    mapview.removeAllAnnotations();
 
    var data = [];
 
    var doc = this.responseXML.documentElement;
 
    var items = doc.getElementsByTagName("item");
    for (var i=0;i<items.length;i++) {
 
        var row = Ti.UI.createTableViewRow();
        row.selectedBackgroundColor = '#fff';
        row.height = 20;
 
        var title = Ti.UI.createLabel({
            color:'#000',
            font:{fontSize:12, fontFamily:'Helvetica Neue'},
            left:10,
            top:2,
            height:'auto',
            width:'auto',
            text:items.item(i).getElementsByTagName("title").item(0).text
        });
        row.add(title);
 
        var locationname = Ti.UI.createLabel({
            color:'#000',
            font:{fontSize:12, fontFamily:'Helvetica Neue'},
            left:110,
            top:2,
            height:'auto',
            width:'auto',
            text:items.item(i).getElementsByTagName("locationname").item(0).text
        });
        row.add(locationname);
 
        var latitude = Ti.UI.createLabel({
            color:'#000',
            font:{fontSize:12, fontFamily:'Helvetica Neue'},
            left:210,
            top:2,
            height:'auto',
            width:'auto',
            text:items.item(i).getElementsByTagName("latitude").item(0).text
        });      
        row.add(latitude);
 
        var longi = items.item(i).getElementsByTagName("latitude").item(0).text;
        var lati = items.item(i).getElementsByTagName("longitude").item(0).text;
 
        // add the annotation here
        var annotation = Titanium.Map.createAnnotation({
            latitude:lati,
            longitude:longi,
            title:items.item(i).getElementsByTagName("title").item(0).text,
            subtitle:'subtitle',
            animate:true,
            customProperty:'customProp'
        });
 
        mapview.addAnnotation(annotation);
 
        data.push(row);
    }
 
    tableView.setData(data);
 
};
 
xhr.onerror = function(e) {
    alert('Network error '+e.error);
};
 
xhr.open('GET',url);
xhr.send();
 
win.open();

— answered 9 months ago by Matt Berg
answer permalink
1 Comment
  • I tried mapview.addAnnotations(annotation);) instead of mapview.addAnnotation(annotation); but now luck, looks beautiful otherwise. :)

    — commented 9 months ago by Martin Andersson

Put your annotation-building loop inside an xhr.onload, and you should be good. That way they won't even be created until there is data there.

Hi Martin, to solve your problem, there are two solutions.

1: use callback function, and call it from xhr.onload function and get the data from that. one benefit is that you will get the value once xhr.onload function is called.
2: you can use app level custom properties. like 
Ti.App.myAnnotations = [];
and then put you data in it...it will never be released until you set Ti.App.myAnnotations = null; or your app is closed or get memory warning from OS(some cases) and you handle that.

— answered 9 months ago by Ashish Nigam
answer permalink
9 Comments
  • The use of Ti.App like this is not good practice. And it doesn't address the asynchronous issue.

    — commented 9 months ago by Jason Priebe

  • thx,I managed to solve it with some help, I dont know if it is the best way but it works for now.

    Titanium.UI.setBackgroundImage('#000');
     
    var win = Titanium.UI.createWindow({ 
     
    });
    win.open();
     
    var tableView = Titanium.UI.createTableView({
        backgroundColor:'white',
        separatorStyle: Titanium.UI.iPhone.TableViewSeparatorStyle.NONE,
        separatorColor: 'transparent'
    });
     
     
    var annotations = []; 
    var annotationObject = [];
    var url ="http://www.test.se/test.xml"; //  rss feed url
    var xhr = Titanium.Network.createHTTPClient();
     
    win.add(tableView);
     
    xhr.open('GET',url);
    xhr.onload = function() {
        var data = [];
     
        // Data is returned from the blog, start parsing
        var doc = this.responseXML.documentElement;
     
     
        // begin looping through blog posts
        var items = doc.getElementsByTagName("item");
        for (var i=0;i<items.length;i++) {
            //
            var row = Ti.UI.createTableViewRow();
            row.selectedBackgroundColor = '#fff';
            row.height = 20;
            //
            var title = Ti.UI.createLabel({
                color:'#000',
                font:{fontSize:12, fontFamily:'Helvetica Neue'},
                left:10,
                top:2,
                height:'auto',
                width:'auto',
                text:items.item(i).getElementsByTagName("title").item(0).text
            });
            row.add(title);
            //
            var locationname = Ti.UI.createLabel({
                color:'#000',
                font:{fontSize:12, fontFamily:'Helvetica Neue'},
                left:110,
                top:2,
                height:'auto',
                width:'auto',
                text:items.item(i).getElementsByTagName("locationname").item(0).text
            });
            row.add(locationname);
     
            var lati = items.item(i).getElementsByTagName("latitude").item(0).text
            var longi = items.item(i).getElementsByTagName("longitude").item(0).text
     
            annotations = JSON.parse('{"latitude":"'+lati+'","longitude":"'+longi+'"}');
            annotationObject.push(annotations);
     
            data.push(row);
        }
     
        tableView.setData(data);
        createMap(); /// OBS
        annotations = [];
    };
     
    xhr.onerror = function(e) {
        alert('Network error '+e.error);
    };
     
     
    xhr.send();
     
    function createMap()
    {
        var test = [];
        for(var i=0; i<annotationObject.length; i++){
            test[i] = Titanium.Map.createAnnotation({
                latitude:annotationObject[i].latitude,
                longitude:annotationObject[i].longitude,
                title:annotationObject[i].title,
                subtitle:annotationObject[i].subtitle,
                animate:true,
                customProperty:annotationObject[i].customProperty
     
            });
        }
     
     
        var mapview = Titanium.Map.createView({
            mapType: Titanium.Map.STANDARD_TYPE,
            region:{latitude:55.6, longitude:13, latitudeDelta:5, longitudeDelta:5},
            animate:true,
            regionFit:true,
            userLocation:true,
            height: 300,
            width:320,
            bottom:0,
            userLocation:true,
            annotations:test
        });
        win.add(mapview);
     
    }

    — commented 9 months ago by Martin Andersson

  • That's exactly the type of solution I was describing. Good work! Now convert your code into a CommonJS module, and you'll have a very nice reusable map window.

    — commented 9 months ago by Jason Priebe

  • Show 6 more comments

Your Answer

Think you can help? Login to answer this question!