ListView: Endless scroll

For demo purposes I’ve used https://designer.mocky.io/design to create an API endpoint that just returns an image url, title and text. Images are fetched from http://lorempixel.com/ (a bit slow smile ).

What it does

The ListView will fetch an initial set of 30 elements and adds a marker at position 10. When the marker is reached during scrolling it will start a new API call and appends that data. If you scroll really fast you’ll see a tiny break at the bottom depending on your API. But you can adjust the return size and the marker position to make a better experience. Of course you don’t want to do it to quickly to save bandwidth.

Code

index.js

var listData = []; // listview data
var rowCount = 0; // row count

function loadData(initial) {
    //
    // make an API request and get data
    //
    var xhr = Ti.Network.createHTTPClient({
        onload: function(e) {
            // just parse the data
            var data = JSON.parse(this.responseText);
            var markerPoint = rowCount + 10;
            var loopData = [];

            // add 30 random elements
            for (var i = 0, len = 30; i < len; ++i) {
                loopData.push({
                    img: {
                        image: data.image + "/sports/Text" + Math.floor(Math.random() * 1000)
                    },
                    text: {
                        text: data.text + " " + (rowCount + 1)
                    },
                    title: {
                        text: data.text + " " + (rowCount + 1)
                    }
                })
                rowCount++;
            }

            if (initial) {
                // set items
                listData = loopData;
                $.lst.sections[0].items = listData;
            } else {
                // append items
                $.lst.sections[0].appendItems(loopData);
            }

            // add a new marker to start a new API call
            $.lst.addMarker({
                sectionIndex: 0,
                itemIndex: markerPoint
            });
        },
        onerror: function(e) {
            Ti.API.debug(e.error);
            alert('error');
        },
        timeout: 5000 // milliseconds
    });
    xhr.open('GET', "https://run.mocky.io/v3/ebb35715-f13e-4ed2-b0c4-b877dcaf3b3c");
    xhr.send();
}

loadData(true);

$.index.open();

function onScroll(e) {
    console.log("Scroll direction: " + e.direction);
}

function onMarker(e) {
    console.log("Hit marker: " + e.itemIndex + " fetch new data.");
    loadData(false);
}

index.xml

<Alloy>
    <Window>
        <ListView id="lst" defaultItemTemplate="default" onScrolling="onScroll" onMarker="onMarker">
            <Templates>
                <ItemTemplate name="default">
                    <ImageView class="img" bindId="img"/>
                    <Label class="lbl_title" bindId="title"/>
                    <Label class="lbl_text" bindId="text"/>
                </ItemTemplate>
            </Templates>
            <ListSection></ListSection>
        </ListView>
    </Window>
</Alloy>

index.tss

"Window" : {
  backgroundColor: "white"
}
"Label" : {
  width: Ti.UI.SIZE,
  height: Ti.UI.SIZE,
  color: "#000",
  touchEnabled: false,
  font: {
    fontSize: 14
  }
}
".img" : {
  left: 0,
  top: 0,
  width: 200,
  height: 200
}
".lbl_title" : {
  left: 220,
  top: 5,
  font: {
    fontWeight: "bold",
    fontSize: 24
  }
}
".lbl_text" : {
  left: 220,
  top: 35
}

Content