Skip to content

Jameson Quave

Using computer technology to educate, and improve lives.

Menu
  • Home
  • Contact
Menu

Developing tvOS Apps for Apple TV [Part 2]

Posted on September 10, 2015September 24, 2015 by Jameson Quave

Looking for some help building your Apple TV tvOS App? I’m available for consulting and development, contact me.

This is part 2 of the tvOS tutorial. If you haven’t gone through part 1 yet, I suggest you run through that first.

Adding Interactivity

In the first section we created a simple TVML document with a few buttons. It looked something like this:

<document>
    <alertTemplate>
        <title>Hello tvOS!</title>
        <button>
            <text>A Button</text>
        </button>
        <button>
            <text>A Second Button</text>
        </button>
    </alertTemplate>
</document>

This is an alert with a few buttons, and they don’t do anything. It’s also rather specific and hard-coded, so maybe what would be better is to generate the XML on the fly. We can do this fairly easily in JS. Let’s add a new function to our main.js file that will encapsulate this alert in to a simpler alert with just an OK button.

function alert(str) {
  var alertXMLString = `<?xml version="1.0" encoding="UTF-8" ?>
  <document>
    <alertTemplate>
      <title>Hey Listen!</title>
      <description>${str}</description>
      <button>
        <text>OK</text>
      </button>
    </alertTemplate>
  </document>`
  var parser = new DOMParser();
  var alertDOMElement = parser.parseFromString(alertXMLString, "application/xml");
  navigationDocument.presentModal(alertDOMElement);
}

What we’re doing here is creating a string called alertXMLString that contains the TVML contents of a simple alert template with just 1 button. However for the description we’re using the TVJS string concatenation ${variable} to inject the value of str.

Next, we create a new DOMParser object that converts this string in to an actual XML DOM element.

Finally, we can present the DOM element modally using the presentModal method of the navigationDocument, a globally defined variable that will always contain the root navigation document.

Now, in our onLaunch function, let’s remove the code we had from before and simply call an alert…

App.onLaunch = function(options) {
    alert("Hello!");
}

tvOS Alert View

Run the app and you’ll see a cool tvOS alert saying “Hello!” However, clicking OK does nothing. So how do we handle event’s such as touch?

Basically, if you want to stay in JavaScript and TVML, you will want to add an event listener to the DOM element. So for example, we could add a second argument to the alert function, so that we can pass in a function that is called when the OK button sends the event for being “selected”. We’ll add this argument and call it doneCallback. To add the event listener, we can simply do so like this:

alertDOMElement.addEventListener("select", function() { doneCallback }, false);

So after updating the entire function, it should look like this:

function alert(str, doneCallback) {
  var alertXMLString = `<?xml version="1.0" encoding="UTF-8" ?>
  <document>
    <alertTemplate>
      <title>Hey Listen!</title>
      <description>${str}</description>
      <button>
        <text>OK</text>
      </button>
    </alertTemplate>
  </document>`
  var parser = new DOMParser();
  var alertDOMElement = parser.parseFromString(alertXMLString, "application/xml");
  alertDOMElement.addEventListener("select", doneCallback, false);
  navigationDocument.presentModal(alertDOMElement);
}

Now, we can modify our original onLaunch function to add a callback function that will present a TVML screen. Before we do that, let’s also add a function called getDocumentContents which similarly implements a callback function when loading is done, which passes in the XMLHttpRequest object’s response to the callbacks only argument. This allows us to more easily load in various types of TVML files.

function getDocumentContents(url, loadCallback) {
  var templateXHR = new XMLHttpRequest();
  templateXHR.responseType = "document";
  templateXHR.addEventListener("load", function() { loadCallback(templateXHR) }, false);
  templateXHR.open("GET", url, true);
  templateXHR.send();
  return templateXHR;
}

This is nearly the same code as the getDocument method we defined earlier, except this is asynchronous and does not actually push anything on to the view.

Now, with this function we can perform this call and then do a screen replace of the alert when the OK button is clicked.

App.onLaunch = function(options) {
    alert("Hello!", function() {
      var helloDocument = getDocumentContents("http://localhost:8000/hello.tvml", function(xhr) {
        navigationDocument.dismissModal();
        navigationDocument.pushDocument(xhr.responseXML);
      });
    });
}

Let’s also change our hello.tvml file to use the stackTemplate, since it’s more interesting to look at. A stackTemplate is a nice way to lay out a list of content with title’s and images. Here’s the example I’ll be using in my demo:

<document>
    <stackTemplate>
        <banner>
            <title>Which Artist Do You Prefer?</title>
        </banner>
        <collectionList>
            <shelf>
                <section>
                    <lockup>
                        <img src="http://localhost:8000/nina.png" width="256" height="256" />
                        <title>Nina Simone</title>
                    </lockup>
                    <lockup>
                        <img src="http://localhost:8000/coltrane.png" width="256" height="256" />
                        <title>John Coltrane</title>
                    </lockup>
                </section>
            </shelf>
        </collectionList>
    </stackTemplate>
</document>

So basically this is just the way a stackTemplate is laid out, the banner is the top banner, the collectionList is just something that contains many shelf objects, which is just something that contains section objects, which contains lockup objects. The lockup object is what actually contains our image and title. In my case I added some images to work with to my directory called nina.png and coltrane.png

tvOS stackTemplate Screenshot

4 thoughts on “Developing tvOS Apps for Apple TV [Part 2]”

  1. Martin says:
    November 5, 2015 at 9:57 am

    Hi,
    I´m a little bit confused 🙂
    The main.js is running on a server. And my tvos app is the client which is connecting to that.

    What is the real world scenario?
    Is the main.js, which i added to the project, running on the AppleTV? Is the real hardware my webserver?
    So localhost is correct?

    Or do I have to deploy my js file on my own dedicated webserver?
    Web programming is new for me…

    regards
    Martin

    Reply
    1. Jameson Quave says:
      November 10, 2015 at 6:09 pm

      You would deploy on a web server, these files are static so all you really need is any basic web host (Digital Ocean for example) with apache installed.

      Reply
  2. Jeremy says:
    January 15, 2016 at 12:09 pm

    Thanks for creating this tutorial, it’s very informative! I am left wondering how to distinguish which element was “clicked on” to perform navigation on user selection. To use your code as reference, The last template you show displays two selections (Nina Simone and John Coletrane). When you user selects John Coletrane and taps the remote to “click” that option how would I proceed to load/navigate to a new template? Let’s say I want to navigate to a different template when Nina Simone is selected. In traditional HTML JQuery this can handled with a small script. So I’m looking for the TVJS counterpart to this.

    $(“sec1″).click(function() {
    window.location.href=”$(this.BASEURL)/Parade.xml.js”;
    });

    It appears we can’t even use id attribute to distinguish, so I assume this would be invalid.

    Nina Simone

    John Coltrane

    Reply
    1. Jameson Quave says:
      February 2, 2016 at 2:40 pm

      You can pretty much add whatever attribute like and listen for the select event. It works how you would expect from web development, except you might find it difficult to use jQuery.

      Reply

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Connect

  • Facebook
  • Google+
  • My Programming Book Picks
  • Twitter

Jameson Quave


I write about new technologies and how we interact with them.
© 2025 Jameson Quave | Powered by Minimalist Blog WordPress Theme