Hour 12. Using Remote Data


What You’ll Learn This Hour:

• Making calls to a remote server using WinJS.xhr

• Parsing RSS and Atom feeds

• Passing different options into WinJS.xhr

• Downloading many types of data

• Forcing an update even if a request is cached locally


Working with local data is needed, but many times apps need to pull data from the Internet. During this hour, we show see some of the ways to connect to outside web services. We explore different ways to consume remote data and how to bring that data into apps.

We work on an RSS Reader app that reads in both RSS content and Atom content. Each post is parsed and stored in an array bound to a ListView. We start with the Split App project and modify the data.js to utilize remote data instead of the local data we have seen so far.

Consuming RSS Feeds

A common example of pulling external data is to consume RSS (Really Simple Syndication) feeds. Atom is another feed format that has the same purpose of RSS but is formatted a little differently. Both file formats are XML.

In this first section, we write a RSS reader app for a single web site. After better understanding how to make a compliant Windows Store app, we cover how to make a full-fledged RSS aggregator app during Hour 19, “Making an App: RSS Aggregator.”

Starting the RSS Reader

We start with the Split App project template and make modifications to add the functionality we seek.

Pulling Down the Feed Posts

Now we can work on actually bringing in remote data to populate the ListView control. We replace the sample data with an actual feed and its corresponding posts.

Cleaning Up the Display

Now it is time to put the finishing touches on the app so that the data we worked so hard to obtain is visible to the user. The project should run in its current state, but many items aren’t bound correctly, and it doesn’t look good.

If we run the app now, we can see on slower machines that the list of posts is rendering in an odd manner. The top item is flickering. This is a performance problem. ListView is trying to update what we are giving it, and we are giving it the entire contents of the posts for every item in the list. This is just too much data—and it is wasted because we are letting the user see only the first couple of lines of the post anyway. To correct this, let’s add another value to the object we are pushing into the feedPosts array inside the getItemsFromXml function in data.js:

feedPosts.push({
    group: feed,
    key: feed.key,
    link: postLink,
    title: postTitle,
    author: postAuthor,
    postDate: postDate,
    content: staticContent,
    shortContent: toStaticHTML(content.textContent.substring(0, 400))
});

The shortContent property contains the first 400 characters of the content of the post. We can just truncate it without worrying about being in the middle of markup because we are wrapping it in toStaticHTML. Truncating at a nonregular text location smoothes things over. Now that we have created the shortContent property, we need to bind it, instead of content, to the innerHTML attribute inside split.html:

<h4 class="item-description"
    data-win-bind="innerHTML: shortContent"></h4>

Now when we run it, we see the same amount of data that we did before, although we are binding much less data to the individual items. This has removed the performance issue for this simple app. We cover how to handle dynamic loading instead of waiting on all items during Hour 19.

At this point, we have completed an RSS reader that retrieves an RSS (or Atom) feed and displays all the posts from that feed in a split view. We modified the built-in data.js template to change from using static data to using dynamic data. In this example, we force the data to load before the page loads. We could load some preloaded data first and then refresh with the latest info after the page loads. We could just display nothing but an updating and progress bar and then display the data after it is loaded. We could display static data and, after successfully loading, store the updated data as the new static data we will load next time the app is run. During Hour 11, “Storing Data Locally,” we explored how to store application data. This would be a great time to do just that. Figure 12.1 shows the results of the RSS Reader.

Image

Figure 12.1. The RSS Reader app connects to the RSS feed and returns every post.

We use this app as a basis to make a more robust app when we are done with the next part of the book, “Making It a Windows Store App.” After we gain the knowledge needed to make our apps utilize the great features that Windows 8 offers, we can create some compelling apps. We convert this modest RSS Reader into a full-fledged Windows Store app during Hour 19.

Digging into WinJS.xhr

The WinJS.xhr function simply calls the XMLHttpRequest function and wraps it in a promise. With IE 10 and Windows Store apps, we can download many different types of data. We can get the content length of the request by using an arraybuffer:

WinJS.xhr({ url: "http://www.microsoft.com", responseType: "arraybuffer" })
.done(function (result) {
    var arrayResponse = result.response;
    var dataview = new DataView(arrayResponse);
    var ints = new Uint32Array(arrayResponse.byteLength / 4);

    xhrDiv1.innerText = "Array is " + ints.length + " uints long";
});

We can download binary data into a blob:

//Video being displayed from: http://www.w3.org/2010/05/video/mediaevents.html
WinJS.xhr({
    url: "http://media.w3.org/2010/05/sintel/trailer.mp4",
    responseType: "blob"
})
.done(function (request) {
    var videoBlob = URL.createObjectURL(request.response, { oneTimeOnly: true });
    var video = document.getElementById("vid");
    video.src = videoBlob;
},
function (err) {
    video.innerHTML = err;
});

We can download XML into a document by using a responseType of document. We can download json into a string:

WinJS.xhr({
    url: "http://api.geonames.org/citiesJSON?" +
        "north=44.1&south=-9.9&east=-22.4&west=55.2&lang=de&username=demo",
    responseType: "json"
})
.done(
    function (request) {
        var geo = JSON.parse(request.responseText);

        var geoname = geo.geonames[0];
        xhrDiv5.innerHTML = geoname.toponymName + ", " + geoname.countrycode;
        xhrDiv6.innerHTML = request.responseText;
    });

The default responseType is text, which is what we used in Hour 10 and in the previous RSS Reader.

The code can be found under Hour12WinJSxhrExample. Figure 12.2 shows the output of the program.

Image

Figure 12.2. Using WinJS.xhr, we can pull down all types of remote data to work with.

Passing Options to WinJS.xhr

We have seen that we can use url and responseType as options to be passed to the xhr function. The rest of the options include those shown in Table 12.1.

Table 12.1. Valid responseType Options for the xhr Function

Image

Setting a Timeout Value on a Request

Sometimes we want to set a timeout on a request. XMLHttpRequest enables us to directly set a timeout, but WinJS.xhr does not. However, we can still set a timeout by doing so on the WinJS.Promise object. WinJS.Promise.timeout cancels the request if it does not complete within the allotted timeout period:

WinJS.Promise.timeout(2500,
    WinJS.xhr({ url: "http://www.microsoft.com" }).then(function () {
        var text = request.responseText;
    }));

This code waits for the request to finish for 2.5 seconds. If it doesn’t return in that time, it cancels the request.

Overriding WinJS.xhr Caching

WinJS.xhr can cache results, to help with performance. But sometimes we want to resend the request to get the latest data, not the cached data. This is done by adding an HTTP header to make sure the request is resent, even it was previously cached. The headers option can have the If-Modified-Since property set to force the request to reach out to the server. For example:

var btnReGet = document.getElementById("btnReGet");
btnReGet.addEventListener("click", reloadMicrosoftdotcom, false);

reloadMicrosoftdotcom();

function reloadMicrosoftdotcom(evt) {
    WinJS.xhr({
        url: "http://www.microsoft.com",
        headers: {
            "IF-MODIFIED-SINCE": "Mon, 27 Mar 1972 00:00:00 GMT"
        }
    })
    .done(function (result) {
        // Report download.
        xhrDiv5.innerText = "Downloaded the page at " + new Date();
    });
}

Further Exploration

We looked at only WinJS.xhr during this hour, but there are many other ways to talk to remote data. The key to most of them is to use the XMLHttpRequest function. We didn’t discuss application caching, but typically when we pull information from the cloud, it is best to cache items so that if users can’t connect to the Internet, they can still use the app. People expect apps to work even if they have no Internet connectivity; we need to make sure that our apps are caching items where appropriate when working with remote resources. Information can be stored in the local application storage, or in some cases, it may make sense to use the Application Cache API to enable offline mode of the app. More information on the Application Cache API can be found at http://msdn.microsoft.com/en-us/library/windows/apps/hh767297.

Another topic that wasn’t discussed was Single Sign-On. Microsoft has the Live SDK, which enables apps to connect to the user’s SkyDrive (beyond what is allowed with Application Data Roaming Storage). More information on SkyDrive integration can be found at http://blogs.msdn.com/b/windowsappdev/archive/2012/03/14/bring-single-sign-on-and-skydrive-to-your-windows-8-apps-with-the-live-sdk.aspx.

We didn’t discuss WebSockets because it is beyond the scope of the book, but Microsoft has an excellent example, listed below. We also didn’t discuss connecting to third-party services such as Facebook or Twitter. Microsoft provides a great example on how to do that. Be sure to check out the Windows SDK samples:

• Connecting with WebSockets sample

• Web authentication broker sample

• XHR, handling navigation errors, and URL schemes sample

Summary

We spent most of the chapter creating an RSS and Atom reader app. We discussed how to utilize the XMLHttpRequest function, called by WinJS and wrapped in a promise. We covered how to parse the XML data we retrieve from the feeds. We also explored how to bind data to our ListView from an outside source. We discussed some of the options we can pass into the WinJS.xhr function and the different types of data we can retrieve by using it. We finished the hour discussing how to send a particular value through the HTTP header information to force a reload and ignore any caching.

Q&A

Q. How do I use WinJS.xhr to post data?

A. Posting data is straightforward, but it does require the type to be set along with the Content-type inside the headers property bag. Of course, it needs any data you are actually posting:

WinJS.xhr({
    type: "post", user: username, password: password,
    url: "https://api.someservice.com/Users/" + username + "/Friends.json",
    headers: { "Content-type": "application/x-www-form-urlencoded" },
    data: data
}).then(success, error);

Q. What application capabilities do I need to set to access the Internet?

A. The default project templates in Visual Studio automatically set the Internet (Client) capability.

Q. How can I update a ListView control after dynamically loading remote data?

A. If a data array wasn’t bound to the ListView before it rendered, a call to listView.ForceLayout(); forces the ListView control to rerender, in which case it read in the data bound at that point. The main purpose of the ForceLayout method is to handle after a view mode change or after displaying the ListView control after it was hidden using display: none.

Workshop

Quiz

1. Because WinJS.xhr doesn’t have a timeout function, we need to use WinJS.Promise.timeout to set a timeout on a request. True or false?

2. How do you turn a JSON string from a service into an actual JavaScript object?

3. How many seconds after launch does an app have to become responsive before the system terminates it?

4. What is the only mandatory property in the options property bag that must be set in WinJS.xhr?

Answers

1. True. XMLHttpRequest has a timeout setting, but it isn’t available through WinJS.xhr. However, we can use the WinJS.Promise.timeout to cancel the request if it goes too long.

2. The JSON.parse function takes a JSON string and returns a JavaScript object:

var obj = JSON.parse(someJSONString);

3. An app has 15 seconds to load after it has launched. If it takes longer than that to complete the app load process, Windows terminates the app. To pass certification, an app can take only 5 seconds to load.

4. The only required value to be passed to WinJS.xhr is the url value. All other properties have defaults.

Activities

1. Add error handling to the RSS Reader app. If an invalid URL is used, make the system handle it gracefully instead of throwing an exception.

2. Format the publish date to be a better display date in the RSS Reader app.

3. Modify the RSS reader app to load static data when it first loads. Then update the ListView (option 1: listView.ForceLayout(); option 2: call the split page’s ready event directly) to change the contents of the ListView control when the updated data is available. At the same time, the data is retrieved; store the data to local app data storage. When the app loads, it should pull from this static data, if present.

4. Connect to a third-party web service (either XML or JSON) and consume the data in your app.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.226.181.57